[HihoCoder-1389] 最大流 仍舊是建圖
阿新 • • 發佈:2018-11-17
題目連結:https://vjudge.net/problem/HihoCoder-1389
題目思路:首先,看到題目,能想到用最大流,可是那個公式始終不能處理,一開始想先二分u,再二分c,因為u增加的快,然後化了一個圖,c二分的話可能某些點就不在原上的,c就會過多,後來一想,算了,列舉吧,然後瘋狂T,想想也覺得會T,就不知道咋辦了,後來看到題解是將最大卡住,因為每次C都在變大,如果u不比之前的小的話,答案也就不比之前的小了,另外還有個優化是,當u取sum/n時仍舊比他大,也要break掉,還有就是我一開始的二分是有問題的,複雜度會高。還有就是sap複雜度是比dinic低的,sap跑1003ms,dinic跑1713ms
AC程式碼
#include<queue> #include<vector> #include<set> #include<cstring> #include<cmath> #include<cstdio> #include<algorithm> using namespace std; #define maxn 500 #define maxm 100000 #define inf 0x3f3f3f3f int first[maxn]; int edge_num; int lev[maxn]; int vis[maxn]; int mark[103]; int n,m; int sum; struct edge{ int u,v; int cap; int next; }e[maxm]; struct node{ int dis; int x; int y; node(int a=0,int b=0,int c=0) { dis=a; x=b; y=c; } }; int low; int high; int xxx; vector<node>nodes; struct point{ int x; int y; int s=0; point(int a=0,int b=0,int c=0) { x=a; y=b; s=c; } }; vector<point>fac; vector<point>pku; void init() { edge_num=0; memset(first,-1,sizeof(first)); } void add_edge(int u,int v,int c) { e[edge_num].u=u; e[edge_num].v=v; e[edge_num].cap=c; e[edge_num].next=first[u]; first[u]=edge_num++; e[edge_num].u=v; e[edge_num].v=u; e[edge_num].cap=0; e[edge_num].next=first[v]; first[v]=edge_num++; } int Dinic_spath(int s,int t) { queue<int>q; q.push(s); memset(lev,-1,sizeof(lev)); memset(vis,0,sizeof(vis)); lev[s]=0; while(!q.empty()) { int u=q.front(); vis[u]=0; q.pop(); for(int k=first[u];k!=-1;k=e[k].next) { int v=e[k].v; if(lev[v]==-1&&e[k].cap>0) { lev[v]=lev[u]+1; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return lev[t]!=-1; } int Dinic_dfs(int u,int t,int flow) { int cost=0; if(u==t) return flow; for(int k=first[u];k!=-1;k=e[k].next) { int v=e[k].v; if(lev[v]==lev[u]+1&&e[k].cap>0) { int minn=Dinic_dfs(v,t,min(e[k].cap,flow-cost)); if(minn>0) { e[k].cap=e[k].cap-minn; e[k^1].cap=e[k^1].cap+minn; cost+=minn; if(cost==flow) break; } else lev[v]=-1; } } return cost; } bool cmp(const node &a,const node &b) { return a.dis<b.dis; } bool judge(int mid,int s,int t) { init(); for(int i=0;i<m;++i) add_edge(s,i+1,mid); for(int i=0;i<n;++i) add_edge(m+i+1,t,fac[i].s); for(int i=0;i<=xxx;++i) add_edge(nodes[i].x+1,m+1+nodes[i].y,inf); int f=0; while(Dinic_spath(s,t)) f+=Dinic_dfs(s,t,inf); return f>=sum; } int main() { while(scanf("%d%d",&n,&m)) { if(n==0&&m==0) break; sum=0; fac.clear(); pku.clear(); nodes.clear(); int x,y,z; for(int i=1;i<=n;++i) { scanf("%d%d%d",&x,&y,&z); fac.push_back(point(x,y,z)); sum+=z; } for(int i=1;i<=m;++i) { scanf("%d%d",&x,&y); pku.push_back(point(x,y,0)); } for(int i=0;i<m;++i) { for(int j=0;j<n;++j) { x=(pku[i].x-fac[j].x)*(pku[i].x-fac[j].x); y=(pku[i].y-fac[j].y)*(pku[i].y-fac[j].y); nodes.push_back(node(x+y,i,j)); } } sort(nodes.begin(),nodes.end(),cmp); memset(mark,0,sizeof(mark)); int j; for(xxx=0,j=0;xxx<nodes.size();++xxx) { if(mark[nodes[xxx].y]==0) { j++; mark[nodes[xxx].y]=1; if(j==n) break; } } high=sum; double ans=1000000007; for(;xxx<nodes.size();++xxx) { int l=sum/n; int r=high; if((double)l*sqrt(sqrt(nodes[xxx].dis))>ans) break; while(l<r) { int mid=(l+r)/2; if(judge(mid,0,n+m+1)) r=mid; else l=mid+1; } high=min(high,r); ans=min(ans,high*sqrt(sqrt(nodes[xxx].dis))); } printf("%d\n",int(ans+0.5)); } }