最短路 ------R - 0 or 1

Given a nn matrix C ij (1<=i,j<=n),We want to find a nn 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 (1<i<n), satisfies ∑X ki (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 (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 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

这道题真的是好题,主要是其他博客都说是好题。。。反正我也不会做。。可能这种解法比较精妙。。
讲解好的博客:https://blog.csdn.net/mengxiang000000/article/details/54234068
解法:
抽象一下模型:
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).
可以看成2~n-1号节点的出度等于入度

所以3个条件可以抽象为最短路中的两种情况(满足1号节点出度为1,n号节点入度为1)
题中没有限制1号节点的入度和n号节点的出度,所以分为两种情况
第一种情况:
1号节点到n号节点的一条最短路径。Xij=1表示需要经过边(i,j),代价为Cij。Xij=0表示不需要经过边(i,j)。记最短路的花费为path
第二种情况:
从1号节点出发走一个环再回到1(至少经过一个点,即不能是自环)的花费c1
从n号节点出发走一个环再回到n(同理)的花费c2
则符合条件的结果即为c1+c2

最终答案为min(path,c1+c2)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
typedef long long LL;
const LL inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double PI = acos(-1);
#define pb push_back
#define mp make_pair
#define fi first
#define se second
const int N = 1005;

int c[N][N];
int dis[N];
bool vis[N];
int n;

void spfa(int s)
{
    memset(dis,inf,sizeof(dis));
    memset(vis,false,sizeof(vis));
    queue<int>que;
    for(int i = 1;i <= n;++i){
        if(s != i){
            vis[i] = true;
            dis[i] = c[s][i];
            que.push(i);
        }
    }
    while(!que.empty())
    {
        int tmp = que.front();
        que.pop();
        vis[tmp] = false;
        for(int i = 1;i <= n;++i){
            if(i != tmp && dis[tmp] + c[tmp][i] < dis[i]){
                dis[i] = dis[tmp] + c[tmp][i];
                if(!vis[i]){
                    vis[i] = true;
                    que.push(i);
                }
            }
        }
    }
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i = 1;i <= n;++i){
            for(int j = 1;j <= n;++j){
                scanf("%d",&c[i][j]);
            }
        }
        spfa(1);
        int p = dis[1],q = dis[n];
        spfa(n);
        p += dis[n];
        printf("%d\n",min(p,q));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值