hdu4370 0 or 1(思维 :最短路模型的转化)!!!

 
 
 

0 or 1

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4398    Accepted Submission(s): 1473


 

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-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.

 

题意:让求 ∑Cij*Xij  的最小值。

这个题目好有意思。

解析转自dalao

转换思维的一道题,虽然是在最短路的专题里看见的,但是一开始真想不到是最短路,还以为是一个求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,且一开始让源点之外的点入队

dalao 的代码: 

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<cstdio>
#include<queue>
#include<stack>

using namespace std;

const int INF = 0x3f3f3f3f;

int cost[305][305];
int dis[305];
int n;
bool vis[305];

void spfa( int start ){
    stack<int> Q;

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

    while( !Q.empty() ){
        int x = Q.top(); Q.pop(); vis[x] = false;

        for( int y = 1; y <= n; y++ ){
            if( x == y ) continue;
            if( dis[x] + cost[x][y] < dis[y] ){
                dis[y] = dis[x] + cost[x][y];
                if( !vis[y] ){
                    vis[y] = true;
                    Q.push( y );
                }
            }
        }
    }
}

int main(){
    ios::sync_with_stdio( false );

    while( cin >> n ){
        for( int i = 1; i <= n; i++ ){
            for( int j = 1; j <= n; j++ ){
                cin >> cost[i][j];
            }
        }

        int ans, c1, cn;
        spfa( 1 );
        ans = dis[n];
        c1 = dis[1];
        spfa( n );
        cn = dis[n];


        cout << min( ans, c1 + cn ) << endl;
    }

    return 0;
}

我的Code:

#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#include<iomanip>
#include<stack>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<algorithm>

using namespace std;
#define read(x) scanf("%d",&x)
#define Read(x,y) scanf("%d%d",&x,&y)
#define sRead(x,y,z)  scanf("%d%d%d",&x,&y,&z)
#define gc(x)  scanf(" %c",&x);
#define mmt(x,y)  memset(x,y,sizeof x)
#define write(x) printf("%d\n",x)
#define INF 0x3f3f3f3f
#define ll long long
#define mod  998244353
const int N = 3005;
const int M=  1e6;
int c[305][305];
int d[305];
bool vis[305];
void spfa(int star,int n)
{
    mmt(vis,0);
    queue<int> Q;
    for(int i = 1; i <= n; ++i)
    {
        if(i == star) continue;
        d[i] = c[star][i];
        vis[i] = 1;
        Q.push(i);
    }
    d[star] = INF;
    while(Q.size())
    {
        int x = Q.front();
        Q.pop();
        vis[x] = 0;
        for(int i = 1; i <= n; ++i)
        {
            if(i == x)  continue;
            if(d[i] >d[x] +c[x][i])
            {
                d[i] = d[x] + c[x][i];
                if(!vis[i])
                {
                    vis[i] = 1;
                    Q.push(i);
                }
            }
        }
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        mmt(c,0);
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= n; ++j)
            {
                read(c[i][j]);
            }
        }
        spfa(1,n);
        int ans = d[n];//1 - n最短路情况
        
        int op1 = d[1];//成环的情况
        spfa(n,n);
        int op2 = d[n];
        
        cout<<min(ans,op1 + op2)<<endl;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值