[uoj389][UNR #3]白鴿【歐拉回路】【射線法】【費用流】

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

# 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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章