【題目鏈接】
http://uoj.ac/problem/389
【題解】
首先存在歐拉回路的條件是所有非孤立點都與一號點連通,並且每個點的度數都是偶數。
一個簡單的想法,把每條邊繞原點旋轉在的角度記爲這條邊的費用(如果是負的就把這條邊反向),我們先把所有的費用都加在一起作爲初始的答案。那麼顯然會有一些點的度數不符合條件。考慮費用流,對於一條邊 我們從 向 連一條費用爲 的邊,表示將這條邊反向。對於 的點,從 向這個點連費用是1,流量爲 , 的點向 連邊。跑最小費用流即可。
由於邊權不一定爲整數,費用流會跑的比較慢。由於繞的圈數一定是整數,所以可以用射線法:從原點射出一條射線,如果邊從左到右跨過費用爲1,反之爲-1。在新圖上做費用流答案就費用是整數了。
費用流的話,每次spfa求出最短路圖,在最短路圖上用dinic增廣即可。
時間複雜度: ?,反正跑的挺快的。
【代碼】
# include <bits/stdc++.h>
# 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);
}