【题目链接】
http://uoj.ac/problem/389
【题解】
首先存在欧拉回路的条件是所有非孤立点都与一号点连通,并且每个点的度数都是偶数。
一个简单的想法,把每条边绕原点旋转在的角度记为这条边的费用(如果是负的就把这条边反向),我们先把所有的费用都加在一起作为初始的答案。那么显然会有一些点的度数不符合条件。考虑费用流,对于一条边 (u,v) ( u , v ) 我们从 u u 向 v v 连一条费用为 2∗这条边费用 2 ∗ 这 条 边 费 用 的边,表示将这条边反向。对于 入度>出度 入 度 > 出 度 的点,从 S S 向这个点连费用是1,流量为 (入度−出度)/2 ( 入 度 − 出 度 ) / 2 , 出度>入度 出 度 > 入 度 的点向 T T 连边。跑最小费用流即可。
由于边权不一定为整数,费用流会跑的比较慢。由于绕的圈数一定是整数,所以可以用射线法:从原点射出一条射线,如果边从左到右跨过费用为1,反之为-1。在新图上做费用流答案就费用是整数了。
费用流的话,每次spfa求出最短路图,在最短路图上用dinic增广即可。
时间复杂度: O(NM) O ( N M ) ?,反正跑的挺快的。
【代码】
# include
# define N 100010
# define ll long long
# define inf 0x3f3f3f3f
# define eps 1e-7
using namespace std;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9'){if (ch == '-') fh = -1; ch = getchar();}
while (ch >= '0' && ch <= '9'){tmp = tmp * 10 + ch - '0'; ch = getchar();}
return tmp * fh;
}
const double pi = acos(-1.0);
struct Node{
int data, next, l, re;
double vote;
}e[N];
struct Edge{
int u, v;
}eg[N];
struct Point{
double x, y;
}p[N];
int n, m, deg[N], use[N], place, head[N], q[N], frm[N], now[N], step[N];
int dis[N], ans;
void buildedge(int u, int v, int w){
e[++place].data = v; e[place].next = head[u]; head[u] = place; e[place].l = w;
}
void build(int u, int v, int l, double w){
e[++place].data = v; e[place].next = head[u]; head[u] = place; e[place].l = l; e[place].vote = w; e[place].re = place + 1;
e[++place].data = u; e[place].next = head[v]; head[v] = place; e[place].l = 0; e[place].vote = -w; e[place].re = place - 1;
}
double cross(Point x, Point y){ return x.x * y.y - x.y * y.x; }
double dot(Point x, Point y){ return x.x * y.x + x.y * y.y; }
void dfs(int x){
for (int ed = head[x]; ed != 0; ed = e[ed].next)
if (use[e[ed].l] == false){
use[e[ed].l] = true;
if (step[e[ed].data] == false){
step[e[ed].data] = true;
dfs(e[ed].data);
}
}
}
double sqr(double x){
return x * x;
}
inline bool spfa(int S, int T){
for(int i = S; i <= T; i++) dis[i] = inf, use[i] = 0;
dis[T] = 0; use[T] = 1;
deque <int> q; q.push_back(T);
while(!q.empty()){
int now=q.front();q.pop_front();
for(int k=head[now];k != 0;k = e[k].next) if(e[e[k].re].l > 0 && dis[e[k].data] > dis[now] - e[k].vote){
dis[e[k].data] = dis[now] - e[k].vote;
if(!use[e[k].data]){
use[e[k].data] = true;
if(!q.empty() && dis[e[k].data] < dis[q.front()])
q.push_front(e[k].data);
else q.push_back(e[k].data);
}
}
use[now]=0;
}
return dis[S] < inf;
}
void bfs(int S, int T){
for(int i = S; i <= T; i++) step[i] = inf;
int pl = 1, pr = 1; q[1] = S, step[S] = 0;
while (pl <= pr && step[T] == inf){
int x = q[pl++];
for (int ed = head[x]; ed != 0; ed = e[ed].next)
if (e[ed].l > 0 && step[e[ed].data] == inf && dis[x] - e[ed].vote == dis[e[ed].data]){
q[++pr] = e[ed].data;
step[e[ed].data] = step[x] + 1;
}
}
}
inline int dfs(int x, int low, int T){
if(x == T) return low;
int used = 0, a;
for(int ed = now[x]; ed != 0; ed = e[ed].next)
if(e[ed].l > 0 && dis[x] - e[ed].vote == dis[e[ed].data] && step[x] + 1 == step[e[ed].data]){
a = dfs(e[ed].data, min(e[ed].l, low - used), T);
if(a) ans -= a * e[ed].vote, e[ed].l -= a, e[e[ed].re].l += a, used += a;
if(used == low){
now[x] = ed;
return used;
}
}
now[x] = 0;
return used;
}
int costflow(int S, int T){
int flow = 0;
while(spfa(S, T)){
for (bfs(S, T); step[T] != inf; bfs(S, T)){
for (int i = S; i <= T; i++) now[i] = head[i];
flow += dfs(S, inf, T);
}
}
return flow;
}
int met(Point x, Point y){
if (x.x * y.x >= 0) return 0;
double num = (0 - x.x) / (y.x - x.x) * (y.y - x.y) + x.y;
return num > 0;
}
int main(){
n = read(), m = read();
for (int i = 1; i <= n; i++)
p[i].x = read(), p[i].y = read();
for (int i = 1; i <= m; i++){
eg[i].u = read(), eg[i].v = read();
buildedge(eg[i].u, eg[i].v, i);
buildedge(eg[i].v, eg[i].u, i);
deg[eg[i].u]++, deg[eg[i].v]++;
}
for (int i = 1; i <= n; i++){
if (deg[i] % 2 == 1){
printf("%d\n", -1);
return 0;
}
}
dfs(1);
for (int i = 1; i <= m; i++)
if (use[i] == false){
printf("%d\n", -1);
return 0;
}
memset(head, 0, sizeof(head)); place = 0;
memset(deg, 0, sizeof(deg));
int S = 0, T = n + 1, num = 0;
for (int i = 1; i <= m; i++){
if (cross(p[eg[i].u], p[eg[i].v]) < 0) swap(eg[i].u, eg[i].v);
if (met(p[eg[i].u], p[eg[i].v]) == 1) num = 1; else num = 0;
ans = ans + num;
deg[eg[i].u]--, deg[eg[i].v]++;
build(eg[i].u, eg[i].v, 1, num * 2);
}
for (int i = 1; i <= n; i++)
if (deg[i] > 0)
build(i, T, deg[i] / 2, 0);
else build(S, i, -deg[i] / 2, 0);
costflow(S, T);
printf("%d\n", ans);
}