1. 程式人生 > >HDU4370(思維最短路徑)

HDU4370(思維最短路徑)

Problem Description
Given a nn matrix Cij (1<=i,j<=n),We want to find a nn matrix Xij (1<=i,j<=n),which is 0 or 1.

Besides,Xij meets the following conditions:

1.X12+X13+…X1n=1
2.X1n+X2n+…Xn-1n=1
3.for each i (1<i<n), satisfies ∑Xki (1<=k<=n)=∑Xij (1<=j<=n).

For example, if n=4,we can get the following equality:

X12+X13+X14=1
X14+X24+X34=1
X12+X22+X32+X42=X21+X22+X23+X24
X13+X23+X33+X43=X31+X32+X33+X34

Now ,we want to know the minimum of ∑Cij*Xij(1<=i,j<=n) you can get.
Hint

For sample, X12=X24=1,all other Xij 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 (1<n<=300).
The 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 Cij(0<=Cij<=100000).

Output
For each case, output the minimum of ∑Cij*Xij 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

題意:
給你一個二維矩陣讓你建立一個新的二維矩陣X使得:
1.X12+X13+…X1n=1
2.X1n+X2n+…Xn-1n=1
3.for each i (1<i<n), satisfies ∑Xki (1<=k<=n)=∑Xij (1<=j<=n).
求 ∑Cij*Xij(1<=i,j<=n)最小值

題解:
可以把這個矩陣看成一個有向圖條件1和條件2 表示定點1的出度為1 定點n的入度為1
其他點的入度與出度相等
就可以轉化為二種可能:
1:求1到n的最短距離
2:1和n都分別各自組成一個環求這個兩個環上的邊和
答案:去上面的最小值

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
using namespace std;
#define clr(a,b) memset(a,b,sizeof(a))
#define il       inline
#define eb(a)    emplace_back (a)
#define pb(a)    push_back(a)
typedef long long ll;
const int maxn=310+2;
const int minn=100+4;
const int inf=0x3f3f3f3f3f;
int n,vis[maxn],dis[maxn],mat[maxn][maxn];
queue<int> qu;
il void  spfa(int a)
{
    clr(vis,0);
    for(int i=1;i<=n;++i)//預處理到每個定點的值因為要求a到a環的大小
    {
        if(i!=a)
        {
            qu.emplace(i);
            vis[i]=1;
            dis[i]=mat[a][i];
        }
    }
    dis[a]=inf;
    while(!qu.empty())
    {
        int nu=qu.front();qu.pop();vis[nu]=0;
        for(int i=1;i<=n;++i)
        {
            if(i==nu){continue;}//因為再當中到其本身是木有意義的
            int tv=mat[nu][i];
            if(dis[i]>dis[nu]+mat[nu][i])
            {
                dis[i]=dis[nu]+mat[nu][i];
                if(!vis[nu])
                {
                    vis[i]=1;
                    qu.emplace(i);
                }
            }
        }
    }
    return ;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=n;++j)
            {
                scanf("%d",&mat[i][j]);
            }
        }
        spfa(1);
        int ans=dis[n];
        int res1=dis[1];
        spfa(n);
        int res2=dis[n];
        printf("%d\n",min(ans,res1+res2));//輸出兩個中最小的那個
    }
    return 0;
}