UOJ#3白鸽
Posted shxnb666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UOJ#3白鸽相关的知识,希望对你有一定的参考价值。
题面
题解
当我刚学欧拉回路的时候,刚刚把网络流学完,就知道欧拉回路的题可以用网络流来做,这道题就是啦。
可以说欧拉回路是一类特殊网络流的调整问题(和上下界网络流)差不多。
所以我曾经开过脑洞,有上下界最小流可以用费用流做,但是由于太慢被自己$D$了。
首先,判断存在性直接用欧拉回路的理论去判就行了,
最后已经知道是绕圈圈了,所以我们考虑如何来计算绕行的圈数。
我们把$x$轴正半轴看成圆点的射线,每正着(从上到下)经过一次,就把答案$+1$,反着经过,就把答案$-1$(为什么?因为说明原来算在里面的一圈假了,所以要$-1$)
答案就是原来的费用加上最大费用最大流。
然后再把每条边随意定向,我发现了$2$个问题。
- 要是定向之后直接符合了判定,就假了。所以我们直接让编号小的向编号大的联就好了。
- 权值有正有负,很麻烦。这样我们直接定向就假设费用都能取到,这样每条边都是负的了,$spfa$就能跑到快一点了(躲开负边就行了)。。。。
#include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 20500 #define S 0 #define T (n+1) #define LL long long #define ri register int #define INF 1000000007 using namespace std; int n,m,x[N],y[N]; int p[N],f[N],vis[N]; int getf(int x) if (x==f[x]) return x; return f[x]=getf(f[x]); inline int read() int ret=0,f=0; char ch=getchar(); while (ch<‘0‘ || ch>‘9‘) f|=(ch==‘-‘),ch=getchar(); while (ch>=‘0‘ && ch<=‘9‘) ret*=10,ret+=(ch-‘0‘),ch=getchar(); return f?-ret:ret; struct graph vector<int> to,w,c; vector<int> ed[N]; LL dis[N]; int cur[N]; bool vis[N]; void add_edge(int a,int b,int aw,int ac) to.push_back(b); w.push_back(aw); c.push_back(ac); ed[a].push_back(to.size()-1); to.push_back(a); w.push_back(0); c.push_back(-ac); ed[b].push_back(to.size()-1); bool spfa() memset(dis,-0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); queue<int> q; dis[S]=0;q.push(S);vis[S]=1; while (!q.empty()) int x=q.front(); q.pop(); for (ri i=0;i<ed[x].size();i++) int e=ed[x][i]; if (dis[to[e]]<dis[x]+c[e] && w[e]) dis[to[e]]=dis[x]+c[e]; if (!vis[to[e]]) vis[to[e]]=1,q.push(to[e]); vis[x]=0; return dis[T]>-INF; int dfs(int x,int lim) if (x==T || !lim) return lim; LL sum=0; vis[x]=1; for (ri &i=cur[x];i<ed[x].size();i++) int e=ed[x][i]; if (dis[x]+c[e]==dis[to[e]] && w[e] && !vis[to[e]]) int f=dfs(to[e],min(lim,w[e])); w[e]-=f; w[1^e]+=f; lim-=f; sum+=f; if (!lim) return sum; return sum; LL zkw() LL ret=0; while (spfa()) memset(vis,0,sizeof(vis)); memset(cur,0,sizeof(cur)); ret+=dfs(S,INF)*dis[T]; return ret; G; int main() n=read(); m=read(); for (ri i=1;i<=n;i++) f[i]=i; for (ri i=1;i<=n;i++) x[i]=read(),y[i]=read(); int ans=0; for (ri i=1;i<=m;i++) int u=read(),v=read(); if (y[u]<0 && y[v]>=0) swap(u,v); vis[u]=vis[v]=1; f[getf(u)]=getf(v); double k=(x[u]==x[v])?-1:(y[v]-y[u]*1.0)/(x[v]*1.0-x[u]); if (y[u]!=y[v] && ( x[u]!=x[v] && y[u]/k<x[u] || x[u]==x[v] && x[u]>0) ) if (y[u]>=0 && y[v]<0) ans++,G.add_edge(v,u,1,-2); else if (y[u]<0 && y[v]>=0) ans--,G.add_edge(v,u,1,2); else G.add_edge(v,u,1,0); else G.add_edge(v,u,1,0); p[u]--; p[v]++; for (ri i=1;i<=n;i++) if (vis[i] && getf(i)!=getf(1)) puts("-1"); return 0; for (ri i=1;i<=n;i++) if (p[i]%2!=0) puts("-1"); return 0; if (p[i]>0) G.add_edge(S,i,p[i]/2,0); else if (p[i]<0) G.add_edge(i,T,-p[i]/2,0); if (n==2) puts("0"); return 0; ans+=G.zkw(); printf("%d\n",ans);
以上是关于UOJ#3白鸽的主要内容,如果未能解决你的问题,请参考以下文章