SPOJ IM - Intergalactic Map - [拆点最大流]

时间:2023-12-18 22:10:38

题目链接:http://www.spoj.com/problems/IM/en/

Time limit:491 ms  Memory limit:1572864 kB  Code length Limit:50000 B

Jedi knights, Qui-Gon Jinn and his young apprentice Obi-Wan Kenobi, are entrusted by Queen Padmé Amidala to save Naboo from an invasion by the Trade Federation. They must leave Naboo immediately and go to Tatooine to pick up the proof of the Federation’s evil design. They then must proceed on to the Republic’s capital planet Coruscant to produce it in front of the Republic’s Senate. To help them in this endeavor, the queen’s captain provides them with an intergalactic map. This map shows connections between planets not yet blockaded by the Trade Federation. Any pair of planets has at most one connection between them, and all the connections are two-way. To avoid detection by enemy spies, the knights must embark on this adventure without visiting any planet more than once. Can you help them by determining if such a path exists? 
Note - In the attached map, the desired path is shown in bold.

Input Description

The first line of the input is a positive integer t ≤ 20, which is the number of test cases. The descriptions of the test cases follow one after the other. The first line of each test case is a pair of positive integers n, m (separated by a single space). 2 ≤ n ≤ 30011 is the number of planets and m ≤ 50011 is the number of connections between planets. The planets are indexed with integers from 1 to n. The indices of Naboo, Tatooine and Coruscant are 1, 2, 3 respectively. The next m lines contain two integers each, giving pairs of planets that have a connection between them.

Output Description

The output should contain t lines. The ith line corresponds to the ith test case. The output for each test case should be YES if the required path exists and NO otherwise.

Example

Input
2
3 3
1 2
2 3
1 3
3 1
1 3

Output
YES
NO

就是1到n共n个点,互相之间有m条边连接,主人公呢想从1出发,经过2,到达3,不走重复路也不走重复点,问你可不可行。

怎么说呢,最大流构图题做的多了,就有点感觉了,大概知道怎么个建图方向了。

首先,瞟了一眼[网络流建模汇总][Edelweiss].pdf上的思路,知道了从2出发,往1和3两个汇点做最大流,这样就可以满足题目要求;

然后我们就建立超级源点s,和超级汇点t,点2连到s上去,cap=2;点1、3都连到t上去,cap=1;

然后我们还要想到一件事情,不能走重复边,很简单,所有题目里给的边的cap都设为1;

那不走重复点呢?就需要拆点,说起来有点玄乎,其实就是原本是个点,然后我们两只手拿住他,吧唧那么一拉,诶就变成了一条边,

显然,我们就记这条拆点边为( from = in(i) , to = out(i) , cap = 1);

这样我们的图就建好了,剩下来的就是dinic了。

 #include<cstdio>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define INF 0x3f3f3f3f
#define MAXN 2*(30011+1000)
using namespace std;
int n,m;
struct Edge{
int u,v,c,f;
};
struct Dinic
{
int s,t;
vector<Edge> E;
vector<int> G[MAXN];
bool vis[MAXN];
int lev[MAXN];
int cur[MAXN];
void init(int n)
{
E.clear();
for(int i=;i<=n;i++) G[i].clear();
}
void addedge(int from,int to,int cap)
{
E.push_back((Edge){from,to,cap,});
E.push_back((Edge){to,from,,});
G[from].push_back(E.size()-);
G[to].push_back(E.size()-);
}
bool bfs()
{
memset(vis,,sizeof(vis));
queue<int> q;
q.push(s);
lev[s]=;
vis[s]=;
while(!q.empty())
{
int now=q.front(); q.pop();
for(int i=;i<G[now].size();i++)
{
Edge edge=E[G[now][i]];
int nex=edge.v;
if(!vis[nex] && edge.c>edge.f)
{
lev[nex]=lev[now]+;
q.push(nex);
vis[nex]=;
}
}
}
return vis[t];
}
int dfs(int now,int aug)
{
if(now==t || aug==) return aug;
int flow=,f;
for(int& i=cur[now];i<G[now].size();i++)
{
Edge& edge=E[G[now][i]];
int nex=edge.v;
if(lev[now]+ == lev[nex] && (f=dfs(nex,min(aug,edge.c-edge.f)))>)
{
edge.f+=f;
E[G[now][i]^].f-=f;
flow+=f;
aug-=f;
if(!aug) break;
}
}
return flow;
}
int maxflow()
{
int flow=;
while(bfs())
{
memset(cur,,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}
}dinic;
int in(int x){return x;}
int out(int x){return x+n;}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);//n个点,m条边
dinic.init(*n+);
for(int i=;i<=m;i++)
{
int from,to;
scanf("%d%d",&from,&to);
if(<=from && from<=n && <=to && to<=n)
{
dinic.addedge(out(from),in(to),);
dinic.addedge(out(to),in(from),);
}
}
dinic.s=, dinic.t=*n+;
dinic.addedge(dinic.s,in(),);
dinic.addedge(out(),dinic.t,);
dinic.addedge(out(),dinic.t,);
for(int i=;i<=n;i++) dinic.addedge(in(i),out(i),i==?:);
if(dinic.maxflow()==) printf("YES\n");
else printf("NO\n");
}
}

PS.听说测试输入边的时候,还会超出范围?不管是不是真的,反正加个if()语句鲁棒一下,无所谓。