HDU - 4370 0 or 1 (最短路)(思维转换)

HDU - 4370  0 or 1 (最短路)(思维转换)(SPFA)

 

Problem Description

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-1 n = 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



题意

给你一个n*n的矩阵,要求你找到一个由0,1组成的n*n的矩阵,使得俩个矩阵对应元素乘积的和最小。

思路

此题可以转换成最短路来写(骚..................)

而求得的0,1矩阵乘以原矩阵,可以看作1为走这条路,0为不走。

对应点乘机的累计和可以看作求1到n的最短路,或点1的最小闭环和点n的最小闭环。为什么?

题意要求的0,1矩阵

1.X12 + X13 + ...X1n = 1         要求点1的出度为1,不存在点1指向1的情况
2.X1n + X2n +...  Xn-1 n = 1    要求点n的入度为1,不存在点n指向n的情况
3.for each i (1<i<n), satisfies  ∑Xki (1<=k<=n) = ∑Xij (1<=j<=n).

                                                     除点1和点n外,其他点的出入度相等。即一定有1到n的路或者有1自环和n自环。

 点1出度为一(条件一),那么一定要到另一个点,如果到n则求1到n的最短路,如果到其他点,由于其他点的出入度要求相同(条件三)

这时需要该点一定有一条出去的边,如果到n则有1到n的最短路,如果不到n点则必然有1-->1的闭环,到其他点(最终都是要到1,n的)。

当有1-->1的自环时,点n的入度为一,则必有一个点指向n,并且只能是点1,n以外的其他点,由于其他点的出入度要求相同(条件三),此时必有n-->n的闭环。

所以一定有1到n的路或  有n的自环和1的自环。

 

所以需要计算1到n的最短路,1自环和n自环的总值,两者最小就为答案

即计算一遍起点为1的d1[n],d1[1],再计算一遍起点为n的d2[n],输出 min(d1[n],d2[1]+d2[n]);

 

值得注意的是这里的最短路写法(spfa)有点不一样,

因为要算起点自环的花费,所以初始化dist[strat]=inf,不能为dist[s]=0,

这样第一遍更新找其他点到起点的距离d就更新不了,

那么可以这样:自己更新第一次,手动将所有的点都加入队列即可。

 

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n;
int dist[310],vis[310];
int mapp[310][310];
void Spfa(int s)
{
    queue<int> q;
    memset(vis,0,sizeof(vis));
    //memset(dist,INF,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        if(i==s)//因为求闭环,源点设置为INF
            dist[i]=INF;
        else
        {
            dist[i]=mapp[s][i];
            q.push(i);
            vis[i]=1;
        }
    }
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=1;i<=n;i++)
        {
            if(dist[i]>dist[u]+mapp[u][i])
            {
                dist[i]=dist[u]+mapp[u][i];
                if(!vis[i])
                    q.push(i),vis[i]=1;
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    while(cin>>n)
    {
        int path,dist1,dist2;
        //path记录1到n的距离,dist2记录点1最小闭环的大小,dist2记录点n最小闭环的大小
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                cin>>mapp[i][j];
        Spfa(1) ,path=dist[n], dist1=dist[1];
        Spfa(n), dist2=dist[n];
        cout<<min(path,dist1+dist2)<<endl;//最短路距离是1到n,和点1闭环+点2闭环中最小的一个
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值