sgu 185 Two shortest 网络流卡内存神题!!!!

方法很多,可以用最短路 + 最大流,也可以用最小费最大流;

费用流有两种做法,一种很容易想到,就是从s连出流量为2的一条边到1,然后求最小费最大流,如果最大流为2,且最小费等于两倍的最短路,就说明存在,只要输出这两条路就可以了;

还有一种费用流的方法是直接两次 spfa 找到最小费用最大流增广每次增广流量增加1,要注意的是逆向的费用,因为题目中的道路是无向的,网络流里的处理方法是加上两条有向边,然后这两条有向边的费用都是这条路的长度,但是费用流里还需要建立一个逆向的费用,费用的值为正向费用的相反数,所以无向图建立费用流一条边就需要要拆成4条边了,这就是费用流比最大流猥琐的地方啊!!!搞得我wa了好久!!!!不过可以耍点小聪明,在 spfa 增广的时候如果当前边的流量为负的话那么就让当前的费用减去这条边的费用(见 66 - 73行的代码),这样就不用再增加边了;

然后就是最短路的方法了,spfa预处理建立一个层次图,第 k 层到第 k + 1的正向容量为1,逆向为0,因为要找两条路,所以试图用 ek 增广两次,每次的流量增加 1,如果能成功说明有两条无相同边的最短路,证明懒得证了~

然后为了防止超内存。。我居然直接把 vector 里的那些变量都改成 short int 了。。。汗。。。第一次。。卡内存真心伤不起,sgu 你有意思不。。。反正哥的 vector 都是要 ac 的,差点又被逼得去敲蛋疼的静态邻接表了,蛋疼。。

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<string>
#include<iomanip>
#include<queue>
#include<cmath>
#include<map>
#include<cstdlib>
#include<stack>
#include<cassert>
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 402;

struct zz
{
    short from;
    short to;
    short c;
    short f;
    short cost;
    short id;
}zx,tz;
int n,m;
vector<zz>g[maxn];
queue<short int>q;
queue<short int>q1,q2;
int way[maxn];
short int backid[maxn];
short int back[maxn];
bool inq[maxn];
bool vis[maxn][maxn];
stack<short int>s;

int spfa()
{
    while(!q.empty())
    {
        q.pop();
    }
    for(int i=1;i<=n;i++)
    {
        way[i] = inf;
    }
    memset(inq,false,sizeof(inq));
    memset(backid,-1,sizeof(backid));
    inq[1] = true;
    way[1] = 0;
    q.push(1);
    int now,to;
    int temp;
    int cost;
    while(!q.empty())
    {
        now = q.front();
        q.pop();
        for(int i=0; i <g[now].size(); i ++)
        {
            to = g[now][i].to;
            cost = g[now][i].cost;
            if(g[now][i].c > g[now][i].f )
            {
                if(g[now][i].f == -1)
                {
                    temp = way[now] - cost;
                }
                else
                {
                    temp = way[now] + cost;
                }
                if( temp < way[to] )
                {
                    way[to] = temp;
                    backid[to] = g[now][i].id;
                    if(!inq[to])
                    {
                        q.push(to);
                        inq[to] = true;
                    }
                }
            }
        }
        inq[now] = false;
    }
    int nowid;
    int idback;
    temp = n;
    while(backid[temp] != -1)
    {
        idback = backid[temp];
        now = g[temp][idback].to;
        nowid = g[temp][idback].id;
        g[now][nowid].f += 1;
        g[temp][idback].f -=1;
        temp = now;
    }
    return way[n];
}

void find()
{
    memset(vis,false,sizeof(vis));
    while(!q.empty())
    {
        q.pop();
    }
    memset(inq,false,sizeof(inq));
    memset(back,0,sizeof(back));
    for(int i=1;i<=n;i++)
    {
        way[i] = inf;
    }
    way[1] = 0;
    inq[1] = true;
    q.push(1);
    int now,to,cost,temp;
    while(!q.empty())
    {
        now = q.front();
        q.pop();
        for(int i=0;i<g[now].size();i++)
        {
            if(g[now][i].f == 1)
            {
                to = g[now][i].to;
                cost = g[now][i].cost;
                temp = way[now] + cost;
                if(temp < way[to])
                {
                    back[to] = now;
                    way[to] = temp;
                    if(!inq[to])
                    {
                        inq[to] = true;
                        q.push(to);
                    }
                }
            }
        }
        inq[now] = false;
    }
    while(!s.empty())
    {
        s.pop();
    }
    temp = n;
    s.push(temp);
    while(back[temp])
    {
        now = back[temp];
        vis[now][temp] = true;
        vis[temp][now] = true;
        s.push(now);
        temp = now;
    }
    while(s.size() > 1)
    {
        cout<<s.top()<<" ";
        s.pop();
    }
    cout<<s.top()<<endl;
    s.pop();
    return ;
}

void find2()
{
    int now=1;
    int to;
    while(now != n)
    {
        for(int i=0;i<g[now].size();i++)
        {
            to = g[now][i].to;
            if(g[now][i].f == 1 && !vis[now][to] )
            {
                printf("%d ",now);
             //   cout<<now<<" ";
                now = to;
                break;
            }
        }
    }
    printf("%d\n",n);
//    cout<<n<<endl;
    return ;
}

void ek()
{
    int ans=spfa();
    if(ans == inf)
    {
        printf("No solution\n");
     //   cout<<"No solution"<<endl;
    }
    if(ans == spfa())
    {
        find();
        find2();
        return ;
    }
    else
    {
        printf("No solution\n");
     //   cout<<"No solution"<<endl;
        return ;
    }
}


int main()
{
    while(cin>>n>>m)
    {
        for(int i=1;i<maxn;i++)
        {
            g[i].clear();
        }
        zx.f=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&zx.from,&zx.to,&zx.cost);
       //     cin>>zx.from>>zx.to>>zx.cost;
            zx.c = 1;
            zx.id = g[zx.to].size();
            g[zx.from].push_back(zx);
            swap( zx.from, zx.to);
            zx.c = 1;
            zx.id = g[zx.to].size() - 1;
            g[zx.from].push_back(zx);
        }
        ek();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值