HDU-4370-0 or 1( 思维最短路 利用矩阵 题目很好)

题目

题意
给你一个二维矩阵让你创建一个新的二维矩阵X使得:
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).
求 ∑Cij*Xij(1<=i,j<=n)最小值


X12+X13+…+X1n=1。 ————————1的出度为1.
1必须要到2 3…n其中一个(只是一个)

X1n+X2n+…+Xn-1 n=1。
1 2 3…n-1 其中一个(只是一个)到n ——————n的入度为1.

第三个条件 到i的和从i出去的是相等的 emm我们就去想最短路…最短路的路径里面正好是一个点进一个点出…

比如。。从2到3,也会有从3到别的,假设到5,(2,3) (3,5)
这样 第3竖排 和 第3横排都有了一个相同的值 是1
可见是很有道理的。。。已知的C矩阵正好是邻接矩阵ma[i][j]的值代表 i到j的边长

此情况为2到n-1的所有点(前提是最短路径经过该点 有入度和出度的时候)入度和出度为1的情况(求1到n的最短路)

另一种是部分点入度和出度为0的情况
也就是1走一个环(不能自身成环) n走一个环(不能自身成环)
虚拟矩阵中走了哪条边就在该位置为1,自然(1,1)和(n,n)的位置都是0

这个题要求闭环 所以不能将起点入队 因为这样d[s]无法初始状态为INF了
dijkstra 和 spfa 的代码都贴一下

//----dijkstra
#include <queue>
#include <cstdio>
#define mak(a,b) make_pair(a,b)
#define pi pair<int,int>
using namespace std;
const int N=300+2;
const int INF=0x3f3f3f3f;
int head[N],d[N];
int tot,n;
struct Edge{int to,len,nex;}edge[N*N+2];
void add(int from,int to,int len)
{
    edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
}
priority_queue<pi,vector<pi>,greater<pi> >q;
void dij(int s)
{
    while(!q.empty())
        q.pop();
    for(int i=1;i<=n;i++)
        d[i]=INF;
    for(int i=head[s];i;i=edge[i].nex)
    {
        int y=edge[i].to,l=edge[i].len;
        if(y==s)       //排除有s-s的边 这个边不为INF时  d[s]!=INF;
            continue;  //自然就没有求起点处闭环的作用了
        d[y]=l;
        if(l!=INF)
            q.push(mak(d[y],y));
    }
    while(!q.empty())
    {
        int x=q.top().second;
        q.pop();
        for(int i=head[x];i;i=edge[i].nex)
        {
            int y=edge[i].to,l=edge[i].len;
            if(d[y]>d[x]+l)
            {
                d[y]=d[x]+l;
                q.push(mak(d[y],y));
            }
        }
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
            head[i]=0;
        tot=0;
        int len;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&len);
                add(i,j,len);
            }
        dij(1);
        int ans1=d[n];//1到n的最短路    2--(n-1)的最短路里面的点入度出度为1
        int op1=d[1];//1单独成环
        dij(n);
        int op2=d[n];//n单独成环
        int ans2=op1+op2;//2--(n-1)的大部分点入度出度为0 环上的点入度为1
        printf("%d\n",ans1<ans2?ans1:ans2);
    }
}

//----spfa
#include <queue>
#include <cstdio>
#define mak(a,b) make_pair(a,b)
#define pi pair<int,int>
using namespace std;
const int N=300+2;
int ma[N][N],d[N];
bool vis[N];
queue<int>q;
int n;
void spfa(int s)
{
    while(!q.empty())
        q.pop();
    for(int i=1;i<=n;i++)
    {
        if(i==s)
        {
            d[i]=INF;
            vis[i]=0;
        }
        else if(ma[s][i]!=INF)
        {
            d[i]=ma[s][i];
            q.push(i);
            vis[i]=1;
        }
        else   //一个小优化 假若INF加进去还要白白循环一边也不会更新任何值
        {
            d[i]=INF;
            vis[i]=0;
        }
    }
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int y=1;y<=n;y++)
        {
            if(d[y]>d[x]+ma[x][y])
            {
                d[y]=d[x]+ma[x][y];
                if(!vis[y])
                {
                    q.push(y);
                    vis[y]=1;
                }
            }
        }
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&ma[i][j]);
        spfa(1);
        int ans1=d[n];//1到n的最短路    2--(n-1)的入度出度为1
        int op1=d[1];//1单独成环
        spfa(n);
        int op2=d[n];//n单独成环
        int ans2=op1+op2;//2--(n-1)的入度出度为0
        printf("%d\n",ans1<ans2?ans1:ans2);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值