loj 1154(最大流+枚举汇点)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26868
思路:拆点,容量为最多能跳的步数,然后设立一个超级源点,源点与各点两连边,容量为一开始的企鹅数,最后就是枚举汇点了,跑最大流验证即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<cmath> 7 using namespace std; 8 #define MAXN 222 9 #define MAXM 222222 10 #define inf 1<<30 11 #define FILL(a,b) memset(a,b,sizeof(a)) 12 13 struct Edge{ 14 int v,cap,next; 15 }edge[MAXM]; 16 17 int n,vs,vt,NV,NE,head[MAXN]; 18 double d; 19 20 21 void Insert(int u,int v,int cap) 22 { 23 edge[NE].v=v; 24 edge[NE].cap=cap; 25 edge[NE].next=head[u]; 26 head[u]=NE++; 27 28 edge[NE].v=u; 29 edge[NE].cap=0; 30 edge[NE].next=head[v]; 31 head[v]=NE++; 32 } 33 34 int level[MAXN],gap[MAXN]; 35 void bfs(int vt) 36 { 37 FILL(level,-1); 38 FILL(gap,0); 39 queue<int>que; 40 que.push(vt); 41 level[vt]=0; 42 gap[0]++; 43 while(!que.empty()){ 44 int u=que.front(); 45 que.pop(); 46 for(int i=head[u];i!=-1;i=edge[i].next){ 47 int v=edge[i].v; 48 if(level[v]!=-1)continue; 49 level[v]=level[u]+1; 50 gap[level[v]]++; 51 que.push(v); 52 } 53 } 54 } 55 56 int pre[MAXN],cur[MAXN]; 57 int SAP(int vs,int vt) 58 { 59 bfs(vt); 60 memcpy(cur,head,sizeof(head)); 61 int u=pre[vs]=vs,aug=inf,maxflow=0; 62 gap[0]=NV; 63 while(level[vs]<NV){ 64 bool flag=false; 65 for(int &i=cur[u];i!=-1;i=edge[i].next){ 66 int v=edge[i].v; 67 if(edge[i].cap>0&&level[u]==level[v]+1){ 68 flag=true; 69 aug=min(aug,edge[i].cap); 70 pre[v]=u; 71 u=v; 72 if(v==vt){ 73 maxflow+=aug; 74 for(u=pre[u];v!=vs;v=u,u=pre[u]){ 75 edge[cur[u]].cap-=aug; 76 edge[cur[u]^1].cap+=aug; 77 } 78 aug=inf; 79 } 80 break; 81 } 82 } 83 if(flag)continue; 84 int minlevel=NV; 85 for(int i=head[u];i!=-1;i=edge[i].next){ 86 int v=edge[i].v; 87 if(edge[i].cap>0&&level[v]<minlevel){ 88 cur[u]=i; 89 minlevel=level[v]; 90 } 91 } 92 if(--gap[level[u]]==0)break; 93 level[u]=minlevel+1; 94 gap[level[u]]++; 95 u=pre[u]; 96 } 97 return maxflow; 98 } 99 100 struct Node{ 101 double x,y; 102 int num,step; 103 }node[MAXN]; 104 105 double Get_Dist(int i,int j) 106 { 107 double d1=(node[i].x-node[j].x)*(node[i].x-node[j].x); 108 double d2=(node[i].y-node[j].y)*(node[i].y-node[j].y); 109 return sqrt(d1+d2); 110 } 111 112 void Build(int ed) 113 { 114 NE=0; 115 FILL(head,-1); 116 vs=0,vt=2*n+1; 117 NV=vt+1; 118 for(int i=1;i<=n;i++){ 119 Insert(i,i+n,node[i].step); 120 Insert(vs,i,node[i].num); 121 } 122 for(int i=1;i<=n;i++){ 123 for(int j=i+1;j<=n;j++){ 124 if(Get_Dist(i,j)<=d){ 125 Insert(i+n,j,inf); 126 Insert(j+n,i,inf); 127 } 128 } 129 } 130 Insert(ed,vt,inf); 131 } 132 133 int main() 134 { 135 int _case,ans,sum,flag,t=1; 136 scanf("%d",&_case); 137 while(_case--){ 138 scanf("%d%lf",&n,&d); 139 sum=0; 140 for(int i=1;i<=n;i++){ 141 scanf("%lf%lf%d%d",&node[i].x,&node[i].y,&node[i].num,&node[i].step); 142 sum+=node[i].num; 143 } 144 flag=0; 145 printf("Case %d:",t++); 146 //枚举集中点 147 for(int i=1;i<=n;i++){ 148 Build(i); 149 if(SAP(vs,vt)==sum)flag=1,printf(" %d",i-1); 150 } 151 if(!flag)printf(" -1"); 152 puts(""); 153 } 154 return 0; 155 }