【题解】Sigitseeing Tour
2024-09-05 22:01:07
题目大意
有一张$n$个结点,$m$条混合边的图($1 \leq n \leq 200$,$1 \leq m \leq 1000$),求这张图是否存在欧拉回路。
题解
因为有混合边,所以我们要先给无向边随机定向,然后再调整方向。
随机定向之后,我们就得到一张有向图。
我们记录每个结点的入度$ind[i]$和出度$outd[i]$,根据欧拉路的性质可以得到,当$ind[i] + outd[i]$为奇数时,一定不存在欧拉路。
对于建边过程,因为原有的有向边不能变向,所以我们可以忽略,只需要将读入的无向边随机定向成有向边即,设容量为$1$即可(每条边只能走一次)。
对于每一个$ind[i] \leq outd[i]$的结点$i$,我们都从源点$s$向$i$连一条有向边,容量为$\frac{outd[i] - ind[i]}{2}$;对于$ind[i] > outd[i]$的结点$i$,从$i$向$t$连一条有向边,容量为$\frac{ind[i] - outd[i]}{2}$。这两种边的含义是连接结点$i$的边中,需要变向的边数。
显然,我们从$s$开始跑一次最大流,最后判断与$s$或$t$相连的边是否满流即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue> #define MAX_N (200 + 5)
#define MAX_M (1000 + 5) using namespace std; struct Edge
{
int to;
int weight;
int next;
}; int T;
int n, m;
int s, t;
int h[MAX_N], tot = ;
Edge e[MAX_N + MAX_M << ];
int ind[MAX_N], outd[MAX_N];
int dep[MAX_N];
int cur[MAX_N];
queue <int> q;
int maxflow; inline void AddEdge(int u, int v, int w)
{
e[++tot].to = v;
e[tot].weight = w;
e[tot].next = h[u];
h[u] = tot;
return;
}; bool BFS()
{
memset(dep, 0x7f, sizeof dep);
memcpy(cur, h, sizeof cur);
q.push(s);
dep[s] = ;
int u, v, w;
while(!q.empty())
{
u = q.front();
q.pop();
for(int i = h[u]; i; i = e[i].next)
{
v = e[i].to;
w = e[i].weight;
if(dep[v] > dep[u] + && w)
{
dep[v] = dep[u] + ;
q.push(v);
}
}
}
return dep[t] != 0x7f7f7f7f;
} int DFS(int u, int flow)
{
if(u == t)
{
maxflow += flow;
return flow;
}
int v, w;
int tmp, sum = ;
for(int i = cur[u]; i && flow; i = e[i].next)
{
cur[u] = i;
v = e[i].to;
w = e[i].weight;
if(dep[v] == dep[u] + && w && (tmp = DFS(v, min(flow, w))))
{
e[i].weight -= tmp;
e[i ^ ].weight += tmp;
sum += tmp;
flow -= tmp;
}
}
return sum;
} void Dinic()
{
while(BFS()) DFS(s, 0x7f7f7f7f);
return;
} int main()
{
scanf("%d", &T);
while(T--)
{
memset(h, , sizeof h);
memset(ind, , sizeof ind);
memset(outd, , sizeof outd);
tot = ;
maxflow = ;
scanf("%d%d", &n, &m);
s = ;
t = n + ;
int u, v, d;
for(int i = ; i <= m; ++i)
{
scanf("%d%d%d", &u, &v, &d);
++outd[u];
++ind[v];
if(!d)
{
AddEdge(u, v, );
AddEdge(v, u, );
}
}
bool isEuler = true;
for(int i = ; i <= n; ++i)
{
if(ind[i] + outd[i] & )
{
isEuler = false;
break;
}
}
if(!isEuler)
{
printf("impossible\n");
continue;
}
int tmp = tot;
for(int i = ; i <= n; ++i)
{
if(ind[i] <= outd[i])
{
AddEdge(s, i, outd[i] - ind[i] >> );
AddEdge(i, s, );
}
else
{
AddEdge(i, t, ind[i] - outd[i] >> );
AddEdge(t, i, );
}
}
Dinic();
for(int i = tmp + ; i <= tot; i += )
{
if(e[i].weight)
{
isEuler = false;
break;
}
}
if(!isEuler) printf("impossible\n");
else printf("possible\n");
}
return ;
}
参考程序
最新文章
- js浮点乘除法运算不精确bug
- JS学习之函数内部属性和方法
- iOS-工作经验+资料分享(长期更新)
- Android http超时选项的测试
- QRTZ_表注释
- Intel Code Challenge Elimination Round (Div.1 + Div.2, combined)(set容器里count函数以及加强for循环)
- Linux Shell 脚本入门
- .NET开发 正则表达式中的 Bug
- JqueryEasyUI教程
- [noip2005提高]过河 dp
- Jersey(1.19.1) - WebApplicationException and Mapping Exceptions to Responses
- java_实现接口的枚举类
- 使用 HTML5、CSS3 和 MathML 在 EPUB 3 中制作版式丰富的出版物
- C#小知识点记录(QQ交流群的一个小问题)Linq提取数据
- “茴”字有四种写法,this也是一样
- 使用spine骨骼动画制作的libgdx游戏
- MySQL数据库快速造大量数据
- Spark SQL官网阅读笔记
- WebView的知识
- [转]CR, LF, CR/LF区别与关系
热门文章
- IO流详解及测试代码
- 【容器化】容器技术实践.pdf_视频学习笔记
- bzoj1430 小猴打架 prufer 序列
- 解析 Java 反射题中一个有趣的坑
- Clean Docker <;none>;:<;none>;
- python学习笔记(七)模块
- prim 模板
- 【Java】java.sql.SQLDataException: Cannot determine value type from string
- C# 高性能 TCP 服务的多种实现方式Cowboy.Sockets
- p5339 [TJOI2019]唱、跳、rap和篮球