最大费用最大流。
建图思路:
起点终点能走两次,限流。
用个map存下string与编号的对应关系,输出方案时走那些走过流量的边。
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
const int N=1005,inf=0x3f3f3f3f;
map<string,int> mp;
bool check;
int n,v,S,T;
string s,b,bpw[N];
int k,head[N],ecnt=1,l[N],r[N],from[N],maxflow,mincost,dis[N],opt[2][N],tot[2];
bool inq[N];
struct Edge {
int to,nxt,val,cost,from;
} e[N*N*2];
void add(int bg,int ed,int val,int cost) {
e[++ecnt].cost=cost;
e[ecnt].from=bg;
e[ecnt].nxt=head[bg];
e[ecnt].to=ed;
e[ecnt].val=val;
head[bg]=ecnt;
}
void insert(int bg,int ed,int val,int cost) {
cost=-cost;
add(bg,ed,val,cost);
add(ed,bg,0,-cost);
}
queue<int>qu;
bool spfa() {
qu.push(S);
std::memset(dis,0x3f,sizeof dis);
dis[S]=0;
inq[S]=1;
while(!qu.empty()) {
int u=qu.front();
qu.pop();
inq[u]=0;
for(int i=head[u],v; i; i=e[i].nxt) {
v=e[i].to;
if(dis[v]>dis[u]+e[i].cost&&e[i].val) {
dis[v]=dis[u]+e[i].cost;
from[v]=i;
if(!inq[v]) qu.push(v),inq[v]=1;
}
}
}
return dis[T]!=inf;
}
void min(int &x,int y) {
x=x<y?x:y;
}
void mcf() {
int x=inf,i=from[T];
while(i) {
min(x,e[i].val);
i=from[e[i].from];
}
maxflow+=x;
i=from[T];
while(i) {
e[i].val-=x;
e[i^1].val+=x;
mincost-=x*e[i].cost;
i=from[e[i].from];
}
}
void dfs(int x,int op) {
opt[op][++tot[op]]=x;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(i&1) continue;
if(e[i^1].val) {
e[i^1].val--;
dfs(v,op);
return;
}
}
}
int main() {
scanf("%d%d",&n,&v);
S=0,T=2*n+1;
for(int i=1;i<=n;i++) cin>>s,mp[s]=i,bpw[i]=s;
insert(S,1,2,0);
insert(n<<1,T,2,0);
insert(1,1+n,2,1);
insert(n,n+n,2,1);
for(int i=2;i<n;i++)
insert(i,i+n,1,1);
for(int i=1;i<=v;i++){
cin>>s>>b;
int st=mp[s],ed=mp[b];
if(st<ed)insert(st+n,ed,1,0);
else insert(ed+n,st,inf,0);
}
while(spfa()) mcf();
if(!maxflow) {puts("No Solution!");return 0;}
if(maxflow==1) {cout<<2<<endl<<bpw[1]<<endl<<bpw[n]<<endl<<bpw[1];return 0;}
cout<<mincost-2<<endl;
dfs(1,0),dfs(1,1);
bool flag=0;
for(int i=1;i<=tot[0];i++) if(opt[0][i]>=1&&opt[0][i]<=n) cout<<bpw[opt[0][i]]<<endl;
for(int i=tot[1];i;i--) {
if(opt[1][i]>=1&&opt[1][i]<=n) {
if(!flag) {
flag=1;
continue;
}
cout<<bpw[opt[1][i]]<<endl;
}
}
return 0;
}