洛谷 P2747 [USACO5.4]周游加拿大Canada Tour 解题报告
P2747 [USACO5.4]周游加拿大Canada Tour
题目描述
你赢得了一场航空公司举办的比赛,奖品是一张加拿大环游机票。旅行在这家航空公司开放的最西边的城市开始,然后一直自西向东旅行,直到你到达最东边的城市,再由东向西返回,直到你回到开始的城市。除了旅行开始的城市之外,每个城市只能访问一次,因为开始的城市必定要被访问两次(在旅行的开始和结束)。
当然不允许使用其他公司的航线或者用其他的交通工具。
给出这个航空公司开放的城市的列表,和两两城市之间的直达航线列表。找出能够访问尽可能多的城市的路线,这条路线必须满足上述条件,也就是从列表中的第一个城市开始旅行,访问到列表中最后一个城市之后再返回第一个城市。
输入输出格式
输入格式:
第 1 行: 航空公司开放的城市数 \(N\) 和将要列出的直达航线的数量 \(V\)。\(N\) 是一个不大于 100 的正整数。\(V\) 是任意的正整数。
第 2..\(N\)+1 行: 每行包括一个航空公司开放的城市名称。城市名称按照自西向东排列。不会出现两个城市在同一条经线上的情况。每个城市的名称都 是一个字符串,最多15字节,由拉丁字母表上的字母组成;城市名称中没有空格。
第 \(N+2\)..N+2+V-1$ 行: 每行包括两个城市名称(由上面列表中的城市名称组成),用一个空格分开。这样就表示两个城市之间的直达双程航线。
输出格式:
Line 1: 按照最佳路线访问的不同城市的数量 M。如果无法找到路线,输出 1。
没想到DP怎么做,于是费用流暴力
发现回来的路其实等价于去的路
建图
1.拆点,费1流1
2.1号和n号点多一条费0流1的点,表示跑两次
3.按原图连边,费0流1
Code:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <map>
using namespace std;
const int N=502;
const int M=30000;
int head[N],to[M],Next[M],edge[M],cost[M],cnt=1;
void add(int u,int v,int w,int c)
{
to[++cnt]=v;edge[cnt]=w;cost[cnt]=c;Next[cnt]=head[u];head[u]=cnt;
to[++cnt]=u;edge[cnt]=0;cost[cnt]=-c;Next[cnt]=head[v];head[v]=cnt;
}
map <string,int > ma;
int n,m,s,t;
void init()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
string name;
cin>>name;
ma[name]=i;
add(i,i+n,1,1);
}
s=1,t=n<<1;
add(s,s+n,1,0);
add(t-n,t,1,0);
for(int i=1;i<=m;i++)
{
string u,v;
cin>>u>>v;
if(ma[u]>ma[v])
swap(u,v);
add(ma[u]+n,ma[v],1,0);
}
}
int dis[N],pre[N],used[N];
bool spfa()
{
queue <int > q;
memset(dis,-0x3f,sizeof(dis));
int inf=dis[s];
dis[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
used[u]=0;
for(int i=head[u];i;i=Next[i])
{
int v=to[i],c=cost[i],w=edge[i];
if(w&&dis[v]<dis[u]+c)
{
pre[v]=i;
dis[v]=dis[u]+c;
if(!used[v])
{
used[v]=1;
q.push(v);
}
}
}
}
return dis[t]!=inf;
}
void work()
{
int maxcost=0,maxflow=0;
while(spfa())
{
maxcost+=dis[t];
maxflow++;
int now=t;
while(pre[now])
{
edge[pre[now]]-=1;
edge[pre[now]^1]+=1;
now=to[pre[now]^1];
}
}
if(maxflow!=2) printf("1\n");
else printf("%d\n",maxcost);
}
int main()
{
init();
work();
return 0;
}
2018.8.2