题意
有一个无向图,求是否能够不重复经过一个点地从1走到2再走到3
思路
首先,可以想到利用网络流来求解,建图的时候,把每一个点拆成两个点,之间连一条容量为1的弧
然后根据原图将每一条弧加入到网络中,注意是像
Pi→P′j
来加边
但是要注意一点,因为是从1走到2再走到3,显然这是很难做的,那么可以换一个思路,假设不是从1走到2再走到3,而是从2开始,不重复经过一个点,走到1和3
这样,构图和求解都变得简单起来了。
从s连一条容量为2的边到2,然后分别从1和3各连一条边到t,做一次最大流,如果最大流为2,那么就有这样的路径,反之没有
可以发现,SPOJ上的题大多数对于空间的限制几乎为没有:
1.5G
?
(这么大哪里用得完,开
10000×10000
的int数组都可以)
但是,时间非常严格,
0.5s
都不到?
而且这一道题数据量很大,结果过了?而且只用了
80ms
?Excuse me?其实刚做的时候觉得Dinic可能过不了,结果过了,说不定用ISAP或者预流推进会更快
代码
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 70111,
MAXM = 603333,
INF = 0x3f3f3f3f;
struct Edge {
int to, cap, flow, _next;
Edge() {
to = cap = flow = _next = 0;
}
};
struct Dinic {
int n, m, s, t;
Edge e[MAXM];
int head[MAXN];
int d[MAXN];
int cur[MAXN];
void init() {
memset(head, -1, sizeof head);
m = 0;
}
void AddEdge(int from, int to, int cap) {
e[m].to = to;
e[m].cap = cap;
e[m]._next = head[from];
e[m].flow = 0;
head[from] = m++;
e[m].to = from;
e[m].cap = 0;
e[m]._next = head[to];
e[m].flow = 0;
head[to] = m++;
}
bool BFS() {
memset(d, 0, sizeof d);
std :: queue < int > Q;
Q.push(s);
while(!Q.empty()) {
int x = Q.front();
Q.pop();
for(int i = head[x]; i != -1; i = e[i]._next) {
if(!d[e[i].to] && e[i].to != s && e[i].cap > e[i].flow) {
d[e[i].to] = d[x] + 1;
Q.push(e[i].to);
}
}
}
return d[t];
}
int DFS(int x, int a) {
if(x == t || a == 0) {
return a;
}
int flow = 0, f;
for(int& i = cur[x]; i != -1; i = e[i]._next) {
if(d[e[i].to] == d[x] + 1 && (f = DFS(e[i].to, min(a, e[i].cap - e[i].flow))) > 0) {
e[i].flow += f;
e[i ^ 1].flow -= f;
flow += f;
a -= f;
if(a == 0) {
break;
}
}
}
return flow;
}
int Maxflow(int s, int t) {
this -> s = s;
this -> t = t;
int flow = 0;
while(BFS()) {
memmove(cur, head, sizeof head);
flow += DFS(s, INF);
}
return flow;
}
} dinic;
void solve() {
int n, m;
scanf("%d%d", &n, &m);
dinic.init();
for(int i = 0; i < m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
if (u < 1 || u > n || v < 1 || v > n) {
continue;
}
dinic.AddEdge(u + n, v, 1);
dinic.AddEdge(v + n, u, 1);
}
const int t = 2 * n + 1;
dinic.AddEdge(0, 2 + n, 2);
dinic.AddEdge(1, t, 1);
dinic.AddEdge(3, t, 1);
for(int i = 4; i <= n; ++i) {
dinic.AddEdge(i, i + n, 1);
}
if(dinic.Maxflow(0, t) == 2) {
printf("YES\n");
} else {
printf("NO\n");
}
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
solve();
}
return 0;
}