HDU 4370 0 or 1(最短)

16697 ワード

0 or 1
Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 692    Accepted Submission(s): 185
Problem Description
Given a n*n matrix C
ij (1<=i,j<=n),We want to find a n*n matrix X
ij (1<=i,j<=n),which is 0 or 1.
Besides,X
ij meets the following conditions:
1.X
12+X
13+...X
1n=1
2.X
1n+X
2n+...X
n-1n=1
3.for each i (1ki (1<=k<=n)=∑X
ij (1<=j<=n).
For example, if n=4,we can get the following equality:
X
12+X
13+X
14=1
X
14+X
24+X
34=1
X
12+X
22+X
32+X
42=X
21+X
22+X
23+X
24
X
13+X
23+X
33+X
43=X
31+X
32+X
33+X
34
Now ,we want to know the minimum of ∑C
ij*X
ij(1<=i,j<=n) you can get.
Hint
For sample, X
12=X
24=1,all other X
ij is 0.
 
 
Input
The input consists of multiple test cases (less than 35 case).
For each test case ,the first line contains one integer n (1The next n lines, for each lines, each of which contains n integers, illustrating the matrix C, The j-th integer on i-th line is C
ij(0<=C
ij<=100000).
 
 
Output
For each case, output the minimum of ∑C
ij*X
ij you can get.
 
 
Sample Input
4 1 2 4 10 2 0 1 1 2 2 0 5 6 3 1 2
 
 
Sample Output
3
 
 
Author
Snow_storm
 
 
Source
2012 Multi-University Training Contest 8
 
 
Recommend
zhuyuanchen520
 
 
1001  (更新された)明らかに、テーマは0/1計画モデルを与えている.
問題を解く鍵はこのモデルの本質をどのように見るかにある.
3つの条件は明らかに未知数の関係を描き、図論の角度から問題を考え、以下の3つの結論を得やすい.
1.X 12+X 13+…X 1 n=1で1番ノードの出度が1
2.X 1 n+X 2 n+…Xn-1 n=1でn番ノードの入度が1
3.ΣXki=ΣXijよって2~n-1番ノードの入度は出度に等しくなければならない
したがって,3つの条件は1番ノードからn番ノードへの経路に等価であるため,Xij=1はエッジ(i,j)を通過する必要があることを示し,その代価はCijである.Xij=0は、エッジ(i,j)を通過しないことを示す.Cijは負ではなく,問題の総コストが最小であることに気づいたので,最適な答えの経路は必ず単純な経路に対応することができる.
最終的に,辺権の隣接行列を直接読み込み,1〜nの最短路を1回走ればよい,最短路をpathと記す.
以上の場合をAとする
非常に非常に非常に非常に非常に申し訳ありませんが、単純なパスは十分な条件ですが、必要ありません.(困ったチームに深くお詫び申し上げます)
次のようなケースが漏れていますB:
1から出発して、1つのリング(少なくとも1つの点を通る、すなわち自環ではない)を歩いて、1に戻る.nから、リング(同理)を歩いて、nに戻ります.
検証しやすく、これはテーマの条件に合っています.そして、A‖Bはこの問題に要求される要件である.
エッジ重みは負ではないので,2つのリングは2つの単純なリングに対応する.
そのため、私たちは1から出発して、最小費用リングを探して、代価をc 1として、nから出発して、最小費用リングを探して、代価をc 2とします.(最短アルゴリズムで重み値を更新するときにレコードを1つ追加するだけでよい:if(i=S)cir=min(cir,dis[u]+g[u][i]))
だから最終答えはmin(path,c 1+c 2)
 
 
/*

HDU 4370 0 or 1

       ,             ,       

              ,   n  ,1     1,

n     1,          ,         ,



      1    n      , Xij=1     

  (i,j),   Cij。Xij=0      (i,j)。   Cij  

          ,                     。



  ,             ,   1 n      ,     path。



       B:

 1  ,    (    1  ,   

   ),  1; n  ,    (  ),  n。

   1 n         1,          0.



      ,             。



       1  ,        ,    c1,

  n  ,        ,    c2。

(                     :if(i==S) cir=min(cir,dis[u]+g[u][i]))



      min(path,c1+c2)

*/

/*

    SPFA      。

                     。

      SPFA        。



   dist[start]  INF。              ,   

           。

*/

#include<stdio.h>

#include<iostream>

#include<string.h>

#include<algorithm>

using namespace std;



const int INF=0x3f3f3f3f;

const int MAXN=330;

int cost[MAXN][MAXN];//           

int dist[MAXN];

int que[MAXN];//

bool vis[MAXN];//        



void SPFA(int start,int n)

{

    int front=0,rear=0;

    for(int v=1;v<=n;v++)//   

    {

        if(v==start)//    start   ,  dist[start]  INF,    

        {

            dist[v]=INF;

            vis[v]=false;

        }

        else if(cost[start][v]!=INF)

        {

            dist[v]=cost[start][v];

            que[rear++]=v;

            vis[v]=true;

        }

        else// dist[start][v]==INF  ,         

        {

            dist[v]=INF;

            vis[v]=false;

        }

    }



    while(front!=rear)//

    {

        int u=que[front++];

        for(int v=1;v<=n;v++)

        {

            if(dist[v]>dist[u]+cost[u][v])

            {

                dist[v]=dist[u]+cost[u][v];

                if(!vis[v])//    

                {

                    vis[v]=true;

                    que[rear++]=v;

                    if(rear>=MAXN) rear=0;//    

                }

            }

        }

        vis[u]=false;

        if(front>=MAXN)front=0;

    }



}

int main()

{

    //freopen("in.txt","r",stdin);

    //freopen("out.txt","w",stdout);

    int n;

    while(scanf("%d",&n)!=EOF)

    {

        for(int i=1;i<=n;i++)

          for(int j=1;j<=n;j++)

            scanf("%d",&cost[i][j]);

        SPFA(1,n);

        int ans=dist[n];//1 n    

        int loop1=dist[1];//1     

        SPFA(n,n);

        int loopn=dist[n];//n     

        ans=min(ans,loop1+loopn);

        printf("%d
",ans); } return 0; }

 
 
次はスタックで実現したSPFA
/*

     SPFA,       

*/

#include<stdio.h>

#include<iostream>

#include<string.h>

#include<algorithm>

using namespace std;

const int MAXN=330;

const int INF=0x3f3f3f3f;



int cost[MAXN][MAXN];

int dist[MAXN];

int Q[MAXN];

bool vis[MAXN];



void SPFA(int start,int n)

{//

    int top=0;

    for(int v=1;v<=n;v++)

    {

        if(v==start)

        {

            dist[v]=INF;

            vis[v]=false;

        }

        else

        {

            dist[v]=cost[start][v];

            vis[v]=true;

            Q[top++]=v;

        }

    }

    while(top!=0)

    {

        int u=Q[--top];

        for(int v=1;v<=n;v++)

        {

            if(dist[v]>dist[u]+cost[u][v])

            {

                dist[v]=dist[u]+cost[u][v];

                if(!vis[v])

                {

                    vis[v]=true;

                    Q[top++]=v;

                }

            }

        }

        vis[u]=false;

    }

}

int main()

{

    //freopen("in.txt","r",stdin);

    //freopen("out.txt","w",stdout);

    int n;

    while(scanf("%d",&n)!=EOF)

    {

        for(int i=1;i<=n;i++)

          for(int j=1;j<=n;j++)

            scanf("%d",&cost[i][j]);

        SPFA(1,n);

        int ans=dist[n];//1 n    

        int loop1=dist[1];//1     

        SPFA(n,n);

        int loopn=dist[n];//n     

        ans=min(ans,loop1+loopn);

        printf("%d
",ans); } return 0; }