sgu 438 The Glorious Karlutka River =) 网络流 动态流

题目大意:有m个人在河的南岸,他们要想到河的北岸。河宽w,每个人每秒可以跳一次,最多跳的距离为D。河中有n个石头,给你石头的坐标(x,y)。每个石头在同一时间最多载人为c。求,m个人都能到南岸的最短时间。


所有人都能到对岸的话,时间不会超过n+m。若D>=W,答案为1。否则,我们按时间拆点。在第一秒的时候,我们把0秒的石头连向汇点,源点连向1秒的石头,0秒的石头连向1秒的石头。注意,这里的连向,是一秒能到的(距离不超过D)。这个时候,跑最大流,若>=m,则说明1秒的时候,m个人都能到对岸。则否,在原图的基础上加边。2秒的时候。我们把1秒的石头连向汇点,源点连向2秒的石头,1秒的石头连向2秒的石头。在第i秒的时候,我们把i-1秒的石头连向汇点,源点连向i秒的石头,i-1秒的石头连向i秒的石头。这里需要注意的是,每秒的石头,仍然需要拆点。限制一个石头的出入边是没有用的。为什么呢?因为,假设一个石头的有多条入边,多条出边。如果你只是限制出入边的话,流经这个石头总的流量也许是超过限制的。实际上,我们每秒的石头都拆点后,其他边可以把容量设为INF就可以了。


//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
//typedef __int64 LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF=1000111222;
const double INFF=1e200;
const double eps=1e-8;
const int mod=1000000007;
const int NN=55;
const int MM=4010;
/* ****************** */

struct G
{
    int v,cap,next;
}E[NN*NN*200],E1[NN*NN*2];
int p[NN*200],T,p1[NN],T1;
int x[NN],y[NN],c[NN];
int temp_p[NN*200],dd[NN*200],qw[NN*200];

void add1(int u,int v)
{
    E1[T1].v=v;
    E1[T1].next=p1[u];
    p1[u]=T1++;
}
void add(int u,int v,int cap)
{
 //  printf("%d->%d:%d\n",u,v,cap);

    E[T].v=v;
    E[T].cap=cap;
    E[T].next=p[u];
    p[u]=T++;

    E[T].v=u;
    E[T].cap=0;
    E[T].next=p[v];
    p[v]=T++;
}

bool find_path(int st,int en,int n)
{
    int i,u,v,head,tail;
    for(i=0;i<=n;i++)
        dd[i]=-1;
    dd[st]=0;
    qw[head=tail=0]=st;
    while(head<=tail)
    {
        u=qw[head++];
        for(i=p[u];i+1;i=E[i].next)
        {
            v=E[i].v;
            if(dd[v]==-1 && E[i].cap>0)
            {
                dd[v]=dd[u]+1;
                qw[++tail]=v;
            }
        }
    }
    return (dd[en]!=-1);
}

int dfs_flow(int u,int& en,int f)
{
    if(u==en || f==0)
        return f;
    int temp,flow=0;
    for( ; temp_p[u]+1 ; temp_p[u] = E[ temp_p[u] ].next)
    {
        G& e=E[temp_p[u]];
        if(dd[e.v]==dd[u]+1)
        {
            temp=dfs_flow(e.v,en,min(f,e.cap));
            if(temp>0)
            {
                f-=temp;
                flow+=temp;
                e.cap-=temp;
                E[temp_p[u]^1].cap+=temp;
                if(f==0)
                    break;
            }
        }
    }
    return flow;
}

int dinic(int st,int en,int n)
{
    int i,ans=0;
    while( find_path(st,en,n) )
    {
        for(i=0;i<=n;i++)
            temp_p[i]=p[i];
        ans+=dfs_flow(st,en,INF);
    }
    return ans;
}

void solve(int n,int sum)
{
    memset(p,-1,sizeof(p));
    T=0;
    int i,j,k,v,ans=0;
    for(i=1;i<=n+sum;i++)
    {
        for(j=p1[0];j+1;j=E1[j].next)
        {
            v=E1[j].v;
            add(0,v+i*n*2,INF);
        }
        for(k=2;k<=n+1;k++)
        {
            for(j=p1[k];j+1;j=E1[j].next)
            {
                v=E1[j].v;
                if(v==1)
                    add(k+i*n*2-n,1,INF);
                else
                    add(k+i*n*2-n,v+i*n*2,INF);
            }
            add(k+i*n*2-n-n,k+i*n*2-n,c[k-1]);
        }
        k=dinic(0,1,i*n*2+n+1);
        ans+=k;
     //   printf("max f==%d\n",k);
        if(ans>=sum)
            break;
    }
    if(i>n+sum)
        puts("IMPOSSIBLE");
    else
        printf("%d\n",i);
}

int main()
{
    int N,M,D,W;
    int i,j;
    while(scanf("%d%d%d%d",&N,&M,&D,&W)!=EOF)
    {
        memset(p1,-1,sizeof(p1));
        T1=0;
        for(i=1;i<=N;i++)
            scanf("%d%d%d",&x[i],&y[i],&c[i]);
        if(D>=W)
        {
            puts("1");
            continue;
        }
        for(i=1;i<=N;i++)
        {
            if(y[i]<=D)
            {
            //    add1(i+1,0);
                add1(0,i+1);
            }
            if(W-y[i]<=D)
            {
                add1(i+1,1);
                add1(1,i+1);
            }
            add1(i+1,i+1);
            for(j=i+1;j<=N;j++)
            {
                if( (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]) <=D*D )
                {
                    add1(i+1,j+1);
                    add1(j+1,i+1);
                }
            }
        }
        c[0]=INF;
        solve(N,M);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值