0 or 1 HDU - 4370 (spfa) 最短路专题

题目描述

Given a n*n matrix Cij (1<=i,j<=n),We want to find a n*n 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.

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.

题目大意:给你一个n*n 的矩阵,让你找出一个满足上述条件的矩阵,使得这两个矩阵每个相同位置相乘的总和最小。

解题思路: 由于在最短路专题做到,可以看出这道题就是把题意转化为最短路的思想。

       把要让我们写出的矩阵看成n个点的邻接矩阵。

       观察让我们写出的矩阵:1、X12+X13+...X1n=1     可以看成是点1的出度为1

                                               2、X1n+X2n+...Xn-1n=1     可以看成点n的入度为1

                                               3、for each i (1<i<n), satisfies ∑Xki (1<=k<=n)=∑Xij (1<=j<=n)    可以看成其它点入度和出度相等

       输入的矩阵即是这n个点相互之间的花费,因此让我们求的就是,1~n的最小花费或者是1的环加上n的环的最小花费。

       答案就是这两者的最小值。

       spfa的有一种操作是可以求单源最小环的,即初始化dis[start] = INF,且一开始让源点之外的点入队

代码:

#include<bits/stdc++.h>
#define ll long long
#define MOD 998244353 
#define INF 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))  
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
int mp[305][305];
int n;
int dis[305];
bool vis[305];

void spfa(int start)
{
    queue<int>Q;
    for(int i=1;i<=n;i++){
       dis[i]=mp[start][i];
       if(i!=start){
          Q.push(i);
          vis[i]=true;
       }else{
          vis[i]=false;
       }
    }
    dis[start]=INF;

    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        vis[u]=false;
        for(int i=1;i<=n;i++){
            if(i==u)continue;
            if(dis[i]>dis[u]+mp[u][i]){
               dis[i]=dis[u]+mp[u][i];
               if(!vis[i]){
                  Q.push(i);
               }
            }
        }
    }
}

int main()
{
   while(~scanf("%d",&n)){
   for(int i=1;i<=n;i++){
      for(int j=1;j<=n;j++){
          scanf("%d",&mp[i][j]);
      }
   }
   spfa(1);
   int num1=dis[n];
   int num2=dis[1];
   spfa(n);
   int num3=dis[n];
   cout<<min(num1,num2+num3)<<endl;
 }
   return 0;
}

 

posted @ 2020-07-28 00:20  hachuochuo  阅读(83)  评论(0编辑  收藏  举报