P2770 航空路线问题

题目戳我
本题有一个套路,就是来回一个圈从a到b在到c可以看成从a到b和c,因为这题是网络流所以考虑建图,像这种网络流建图一个点只能通过一次的图,一般情况下都是要拆点的.然后拆点后就要考虑边的容量和cost的分布了,边的容量那么终点和起点都是2其他都是1,cost都为1,因为都是一个点,最后答案再减去2以为起点和终点都经过了两次。如果最后求得的流量是2,说明有两条路径,如果是1的话可能存在1直接到n这种情况,特判一下就好了,其余的都无法到达,具体看代码吧。

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define ull unsigned long long
#define se second
#define endl "\n"
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn =3e3 + 5;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const double  lnf  = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const int p=1e7+233;
const  double pi=3.141592653589;
string s[105];
map<string,int>mp;
int n,v;
int len,head[maxn];
struct node
{
    int fa,to,next,c,cost;
}a[maxn<<2];
void add(int u,int v,int c,int cost)//输入cost的相反数求最大费用流
{
    a[len].fa=u,a[len].c=c,a[len].cost=cost,a[len].to=v,a[len].next=head[u],head[u]=len++;

    a[len].fa=v,a[len].c=0,a[len].cost=-cost,a[len].to=u,a[len].next=head[v],head[v]=len++;
}

int dis[maxn],vis[maxn],pre[maxn];

bool spfa(int s,int t)
{
    queue<int>q;
    for(int i=0;i<=t;i++)
    {
        vis[i]=0;
        dis[i]=inf;
        pre[i]=-1;
    }
    dis[s]=0;
    q.push(s);
    vis[s]=1;
    while(!q.empty())
    {

        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=a[i].next)
        {
            if(a[i].c>0)
            {
                int v=a[i].to;
            if(dis[v]>dis[u]+a[i].cost)
            {
                dis[v]=dis[u]+a[i].cost;
                pre[v]=i;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
            }
        }
    }//bug;
    return dis[t]!=inf;
}

void init()
{
    ms(head,-1);
    len=0;
}
int flow_sum=0;
int f(int s,int t)//s是源点,t是汇点.
{
    int ans=0,flow;
    while(spfa(s,t))
    {
        //bug;
        flow=inf;
        for(int i=pre[t];~i;i=pre[a[i].fa])
        {
            if(a[i].c<flow)
                flow=a[i].c;
        }
        for(int i=pre[t];~i;i=pre[a[i].fa])
        {
            a[i].c-=flow;
            a[i^1].c+=flow;
        }
        ans+=dis[t]*flow;
       // printf("%d\n",dis[en]*flow);
        flow_sum+=flow;
    }
    return ans;
}
int pat[maxn];
void dfs1(int x)
{
    pat[x]=1;
    cout<<s[x-n]<<endl;
    for(int i=head[x];i+1;i=a[i].next)
    {
        int to=a[i].to;
        if(to<=n&&!a[i].c)
        {
            dfs1(to+n);
            break;
        }
    }
}
void dfs2(int x)
{
    for(int i=head[x];i+1;i=a[i].next)
    {
        int to=a[i].to;
        if(to<=n&&!a[i].c&&!pat[to+n])
        {
            dfs2(to+n);
        }
    }
    cout<<s[x-n]<<endl;
}
int main()
{
    init();
    ms(pat,0);
    IOS;
    cin>>n>>v;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        mp[s[i]]=i;
    }
    for(int i=2;i<n;i++)
    {
        add(i,i+n,1,-1);//因为我的模板是最小费用流,而题目意思是最大费用,所以加个负号。
    }
    bool flage=false;
    add(1,n+1,2,-1),add(n,n+n,2,-1);
    for(int i=1;i<=v;i++)
    {
        string a,b;
        cin>>a>>b;
        int x=mp[a];
        int y=mp[b];
        if(x>y)swap(x,y);
        if(x==1&&y==n)
        {
            flage=true;
        }
        add(x+n,y,1,0);//从一个点到另一个点
    }
    int ans=f(1,2*n);
    if(flow_sum==2)
    {
       cout<<-ans-2<<endl;
    }
    else if(flow_sum==1&&flage)//特判一下
    {
        cout<<"2"<<endl;
        cout<<s[1]<<" "<<s[n]<<" "<<s[1]<<endl;
        return 0;
    }
    else
    {
        cout<<"No Solution!"<<endl;
        return 0;
    }
    dfs1(1+n);
    dfs2(1+n);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qcccc_/article/details/107818718