目录
显示
题目链接
https://www.luogu.com.cn/problem/P2770
题解
我们的任务是在图上找两条只在起点和终点相交的路径。
将点 \(x\) 拆分成 \(x_1,x_2\)。对于除了起点和终点之外的其他点,连 \(x_1 \to x_2\),流量为 \(1\)(只允许经过一次),费用为 \(0\) 的边。而对于起点和终点,连 \(x_1 \to x_2\),流量为 \(2\)(要经过两次),费用为 \(0\) 的边。
对于 \(u \to v\) 这样一条路径,连一条 \(u_2 \to v_1\),流量为 \(1\),费用为 \(1\) 的边。
跑最大费用最大流即可。如果最大流等于 \(2\) 则有解。费用即为经过的城市数。
特别地,当最大流等于 \(1\) 时,可能存在一条 \(s \to t \to s\) 的路径,需要特判这种情况。
输出方案的话,直接在残量网络上 DFS 两次寻找路径即可。注意第二次 DFS 的时候需要倒序输出。
#include <cstring>
#include <iostream>
#include <string>
#include <map>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
map<string,int> m1;
map<int,string> m2;
struct edge
{
int v,w,c,next;
}e[80005];
struct node
{
int v,e;
}p[205];
int head[205],dis[205],vis[205];
int n,m,s,t,cnt=1,maxw,minf;
void addedge(int u,int v,int w,int c)
{
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].c=c;
e[cnt].next=head[u];
head[u]=cnt;
}
bool spfa()
{
queue<int> q;
memset(dis,INF,sizeof(dis));
dis[s]=0,vis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].next)
if(e[i].w&&dis[u]-e[i].c<dis[e[i].v])
{
dis[e[i].v]=dis[u]-e[i].c;
p[e[i].v].v=u;
p[e[i].v].e=i;
if(!vis[e[i].v])
{
vis[e[i].v]=1;
q.push(e[i].v);
}
}
}
return dis[t]!=INF;
}
void dfs1(int u)
{
vis[u]=1;
cout<<m2[u-n]<<endl;
for(int i=head[u];i;i=e[i].next)
if(e[i].v<=n&&!e[i].w)
{
dfs1(e[i].v+n);
break;
}
}
void dfs2(int u)
{
for(int i=head[u];i;i=e[i].next)
if(e[i].v<=n&&!vis[e[i].v+n]&&!e[i].w)
dfs2(e[i].v+n);
cout<<m2[u-n]<<endl;
}
int main()
{
bool flag=false;
cin>>n>>m;
s=1,t=2*n;
for(int i=1;i<=n;i++)
{
string str;
cin>>str;
m1[str]=i;
m2[i]=str;
if(i==1||i==n)
{
addedge(i,i+n,2,0);
addedge(i+n,i,0,0);
}
else
{
addedge(i,i+n,1,0);
addedge(i+n,i,0,0);
}
}
for(int i=1;i<=m;i++)
{
string s,t;
cin>>s>>t;
int u=m1[s],v=m1[t];
if(u==1&&v==n)flag=true;
addedge(u+n,v,1,1);
addedge(v,u+n,0,-1);
}
while(spfa())
{
int minw=INF;
for(int i=t;i!=s;i=p[i].v)
minw=min(minw,e[p[i].e].w);
for(int i=t;i!=s;i=p[i].v)
{
e[p[i].e].w-=minw;
e[p[i].e^1].w+=minw;
}
maxw+=minw;
minf+=minw*dis[t];
}
if(maxw!=2&&!flag)cout<<"No Solution!"<<endl;
else if(maxw!=2&&flag)
{
cout<<2<<endl;
cout<<m2[1]<<endl<<m2[n]<<endl<<m2[1]<<endl;
}
else
{
cout<<-minf<<endl;
dfs1(n+1);
dfs2(n+1);
}
return 0;
}