poj 3498(枚举加最大流dinic)

这个题需要自己建一个超级源点,建边 s -> i -> i ' ; s->i 容量为 i 点企鹅的数量,i到 i ' 容量为能跳多少次,然后枚举到每一个点的最大流,如果等于企鹅的总数,记录这个点。。最后把所有能到达的点从小到大输出即可。。。。。

这里我刚开始的数组小了。。各种tle。。。。提醒一下吧。。。。  


#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
using namespace std;
const int inf=1<<30;
const int maxn=100000;
#define cc(m,v) memset(m,v,sizeof(m))
struct node{
    int u,v,f,next;
}edge[maxn];
int head[220],p,lev[220],cur[220];
int que[maxn];
void ainit(){
    p=0,cc(head,-1);
}
bool bfs(int s,int t){
    int i,u,v,qin=0,qout=0;
    cc(lev,0),lev[s]=1,que[qin++]=s;
    while(qout!=qin){
        u=que[qout++];
        for(i=head[u];i!=-1;i=edge[i].next)
            if(edge[i].f>0 && lev[v=edge[i].v]==0){
                lev[v]=lev[u]+1,que[qin++]=v;
                if(v==t) return 1;
            }
    }
    return lev[t];
}
int dinic(int s,int t){
    int i,k,u,qin,f;
    int flow=0;
    while(bfs(s,t)){
        memcpy(cur,head,sizeof(head));
        u=s,qin=0;
        while(1){
            if(u==t){
                for(k=0,f=inf;k<qin;k++)
                    if(edge[que[k]].f<f)
                        f=edge[que[i=k]].f;
                for(k=0;k<qin;k++)
                    edge[que[k]].f-=f,edge[que[k]^1].f+=f;
                flow+=f,u=edge[que[qin=i]].u;
            }
            for(i=cur[u];cur[u]!=-1;i=cur[u]=edge[cur[u]].next)
                if(edge[i].f>0 && lev[u]+1==lev[edge[i].v]) break;
            if(cur[u]!=-1)
                que[qin++]=cur[u],u=edge[cur[u]].v;
            else{
                if(qin==0) break;
                lev[u]=-1,u=edge[que[--qin]].u;
            }
        }
    }
    return flow;
}
void addedge(int u,int v,int f){
    edge[p].u=u,edge[p].v=v,edge[p].f=f,edge[p].next=head[u],head[u]=p++;
    edge[p].u=v,edge[p].v=u,edge[p].f=0,edge[p].next=head[v],head[v]=p++;
}
int main(){
    int n,i,j,s,cas,sum,flag;
    int ans[110],m,v,x[110],y[110];
    double len;
    scanf("%d",&cas);
    while(cas--){
        scanf("%d%lf",&n,&len);
        ainit();
        for(i=0,s=n<<1,sum=0;i<n;i++){
            scanf("%d%d%d%d",&x[i],&y[i],&m,&v);
            if(m) addedge(s,i,m),sum+=m;
            addedge(i,i+n,v);
        }
        len=len*len;
        for(i=0;i<n;i++) for(j=i+1;j<n;j++)
            if(pow((double)x[i]-x[j],2)+pow((double)y[i]-y[j],2)<=len)
                addedge(i+n,j,inf),addedge(j+n,i,inf);
        for(i=0,flag=0;i<n;i++){
            for(j=0;j<p;j+=2) edge[j].f+=edge[j^1].f,edge[j^1].f=0;
            ans[i]=(dinic(s,i)==sum),flag+=ans[i];
        }
        if(!flag) printf("-1");
        else{
            for(i=0;i<n;i++) if(ans[i])
                printf("%d ",i);
        }
        printf("\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值