UVA12125
前言
这道题还是有一些坑点的,例如本人就因为最后不能多输出空格而被卡了半天。
思路
我们进入正题,这道题一拿到题就知道是网络流对吧。那么现在就纠结于如何建图了对吧,我们首先就能想到第 \(i\) 个点分成 \(i\) 和 \(i+n\)。那么我们这样做有什么好处呢?这其实是为了能跳出多少次,我们只需要先将 \(i\) 的企鹅所有能跳的跳到 \(i+n\) 那里去,因为我们即使有再多的企鹅但又跳不出去也没什么用。然后,我们就要考虑去枚举以下终点是谁了,然后再在里面进行建图,我们令起点为 \(0\) 好吧,那么我们就对于每一个点都连上一条流量为企鹅只数的边,然后再按照上述步骤从 \(i\) 到 \(i+n\) 连上一条流量为最大跳跃次数的边。随后我们就可以去考虑不同的点之间的跳跃了,我们还是枚举一个 \(i\) 和 \(j\) 然后判断一下两个点距离是否小于等于 \(d\) 若满足条件则可以将 \(i+n\) 连上 \(j\) 以及将 \(j+n\) 连上 \(i\) 这里为什么是 \(i+n\) 和 \(j+n\) 就是因为要加了 \(n\) 的点才是存的真实能跳出去的只数,这里的两条边的流量都为最大值即可毕竟没规定能跳两个点之间能跳多少只嘛!最后再将 \(i\) 和终点连上一条流量为最大值的边,然后就是去跑最大流了,最后判断最大流是否等于总只数,若满足则记录下来方便输出。
代码
#include <bits/stdc++.h>
using namespace std ;
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define rep1(i,x,y) for(int i=x;i>=y;i--)
#define fire signed
const int N=1e5+10;
int T,n,s,t,cnt;
double d;
int head[1005],tot,zong;
int hu[N];
int dx[1005],dy[1005];
int sum[1005],walk[1005],dis[1005],vis[1005];
struct node {
int x,y,z;
} edg[N];
inline void add(int x,int y,int z) {
edg[++tot]= {y,head[x],z};
head[x]=tot;
edg[++tot]= {x,head[y],0};
head[y]=tot;
}
inline double ju(int i,int j) {//求距离
double xx=dx[i]-dx[j],yy=dy[i]-dy[j];
return 1.0*sqrt(1.0*xx*xx+1.0*yy*yy);
}
inline void build() {//建图
tot=1;
memset(head,0,sizeof head);
memset(edg,0,sizeof edg);
rep(i,1,n) {
add(s,i,sum[i]);
add(i,i+n,walk[i]);
rep(j,i+1,n) {
if(ju(i,j)<=d) {
add(i+n,j,INT_MAX);
add(j+n,i,INT_MAX);
}
}
}
}
inline bool bfs() {
queue<int>q;
memset(dis,0,sizeof dis);
dis[s]=1;
q.push(s);
while(!q.empty()) {
int x=q.front();
q.pop();
for(int i=head[x]; i; i=edg[i].y) {
int to=edg[i].x;
if(edg[i].z&&!dis[to]) {
dis[to]=dis[x]+1;
if(to==t) return true;
q.push(to);
}
}
}
return false;
}
inline int dinic(int x,int flow) {
if(x==t) return flow;
int k=0,plus=0;
for(int i=hu[x]; i&&flow; i=edg[i].y) {
hu[x]=i;
int to=edg[i].x;
if(dis[to]==dis[x]+1&&edg[i].z) {
k=dinic(to,min(edg[i].z,flow));
if(!k) dis[to]=false;
plus+=k;
edg[i].z-=k;
edg[i^1].z+=k;
flow-=k;
}
}
return plus;
}
fire main() {
cin>>T;
while(T--) {
zong=cnt=0;
cin>>n;
scanf("%lf",&d);
s=0,t=2*n+1;
rep(i,1,n) {
scanf("%d%d",&dx[i],&dy[i]);
cin>>sum[i]>>walk[i];
zong+=sum[i];//记录总企鹅数
}
rep(i,1,n) {
build();
add(i,t,INT_MAX);
int maxflow=0;
while(bfs()) {//模板最大流不讲了相信能来到这道题的人都会
memcpy(hu,head,sizeof head);
maxflow+=dinic(s,INT_MAX);
}
if(maxflow==zong) vis[++cnt]=i; //是否满足条件满足则存答案
}
if(!cnt) { //没有答案
cout<<"-1\n";
} else {
printf("%d",vis[1]-1); //注意要减一
rep(i,2,cnt) printf(" %d",vis[i]-1);
cout<<"\n";
}
}
return false;//AC了
}

浙公网安备 33010602011771号