HDU-4370 0 or 1( 最短路 )

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4370

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 (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
 
转换思维的一道题,虽然是在最短路的专题里看见的,但是一开始真想不到是最短路,还以为是一个求min( c[1][n], c[1][k] + c[k][n] )( 1 < k < n )的水题,不过认真看完题解发现转换思维之后确实是一道水题,难就难在转换思维
理解条件之前先转换一下思维, 将矩阵C看做描述N个点花费的邻接矩阵
再来看三个条件:
条件一:表示1号点出度为1
条件二:表示n号点入度为1
条件三:表示k( 1 < k < n )号点出度等于入度
最后再来看看题目要求,∑Cij*Xij(1<=i,j<=n),很明显,这是某个路径的花费,而路径的含义可以有以下两种:
一:1号点到n号点的花费
二:1号点经过其它点成环,n号点经过其它点成环,这两个环的花费之和
于是,就变成了一道简单的最短路问题
关于环花费的算法,可以改进spfa算法,初始化dis[start] = INF,且一开始让源点之外的点入队
代码如下
 
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<map>
 6 #include<cstdio>
 7 #include<queue>
 8 #include<stack>
 9 
10 using namespace std;
11 
12 const int INF = 0x3f3f3f3f;
13 
14 int cost[305][305];
15 int dis[305];
16 int n;
17 bool vis[305];
18 
19 void spfa( int start ){
20     stack<int> Q;
21 
22     for( int i = 1; i <= n; i++ ){
23         dis[i] = cost[start][i];
24         if( i != start ){
25             Q.push( i );
26             vis[i] = true;
27         }
28         else{
29             vis[i] = false;
30         }
31     }
32     dis[start] = INF;
33 
34     while( !Q.empty() ){
35         int x = Q.top(); Q.pop(); vis[x] = false;
36 
37         for( int y = 1; y <= n; y++ ){
38             if( x == y ) continue;
39             if( dis[x] + cost[x][y] < dis[y] ){
40                 dis[y] = dis[x] + cost[x][y];
41                 if( !vis[y] ){
42                     vis[y] = true;
43                     Q.push( y );
44                 }
45             }
46         }
47     }
48 }
49 
50 int main(){
51     ios::sync_with_stdio( false );
52 
53     while( cin >> n ){
54         for( int i = 1; i <= n; i++ ){
55             for( int j = 1; j <= n; j++ ){
56                 cin >> cost[i][j];
57             }
58         }
59 
60         int ans, c1, cn;
61         spfa( 1 );
62         ans = dis[n];
63         c1 = dis[1];
64         spfa( n );
65         cn = dis[n];
66 
67 
68         cout << min( ans, c1 + cn ) << endl;
69     }
70 
71     return 0;
72 }

 

将矩阵C看做描述N个点花费的邻接矩阵

转载于:https://www.cnblogs.com/hollowstory/p/5670128.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值