hdu4370 0 or 1 最短路

本文探讨了一种解决特定矩阵问题的算法,该算法通过构建特定的矩阵结构和应用图论原理来找到满足条件的最优解。通过实例分析,详细解释了如何在给定条件下求解最小值,并提供了解题过程中的关键思路和步骤。本文强调了理解题目隐含意义的重要性,以及正确应用算法解决实际问题的方法。
摘要由CSDN通过智能技术生成
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.
Sample Input
  
  
4 1 2 4 10 2 0 1 1 2 2 0 5 6 3 1 2
 

Sample Output
  
  
3

在比赛的时候我的思路是X矩阵只可能是0 or 1,所以分为三种情况,分别求出最小值,然后再取最小值。

但是后来发现还是有少情况的时候。反正就是没往图论的方向想,赛后看解题报告,才恍然大悟。

这道题关键在于看懂题的隐含意思。

三个条件可以理解为:第一个点出度为1,最后一个点入度为0. 据说在比赛时的数据水了,没有考虑有环的情况。

因为第一个点有可能有入度,最后一个点也可能有出度。所以还可以看做是第一个点的一个环和最后一个点的一个环的和。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxint=1e7;
const int mm=400;
const int mn=1111111;
int dis[mm],head[mm],q[mm],vis[mm];
int c[mm][mm];
int n,edge;
int ver[mn],next[mn],cost[mn];
void addedge(int u,int v,int c)
{
    ver[edge]=v,cost[edge]=c,next[edge]=head[u],head[u]=edge++;
}
int spfa(int src)
{
    int i,u,v,l,r=0,tmp,cir;
    for(i=0;i<=n;i++)    dis[i]=maxint;
    dis[q[r++]=src]=0;
    vis[src]=1;
    cir=maxint;
    for(l=0;l!=r;(++l>mm)?l=0:l)//第三个条件非常重要,这个也给忘记了,呜呜。。。。
        for(i=head[u=q[l]],vis[u]=0;i>=0;i=next[i])
        {
            if(ver[i]==src&&dis[u]+cost[i]<cir) cir=dis[u]+cost[i];
            if(dis[v=ver[i]]>(tmp=dis[u]+cost[i]))
            {
                dis[v]=tmp;
                if(vis[v])  continue;
                vis[q[r++]=v]=1;
                if(r>=mm)   r=0;
            }
        }

    return cir;
}
int main()
{
    int i,j,tot,ans;
    while(~scanf("%d",&n))
    {
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                scanf("%d",&c[i][j]);
        edge=0;
        memset(head,-1,sizeof(head));//忘记初始化head了,找了好长时间。。。
        memset(vis,0,sizeof(vis));
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
            if(i!=j)
                addedge(i,j,c[i][j]);
        ans=spfa(1);
        tot=dis[n];
        int ans1=spfa(n);
        ans=min(tot,ans+ans1);
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值