UVA10983 Buy one, get the rest free 拆点+ 网络流+二分

二分最小费用,小于等于这个费用的边要连起来。

把一个城市看做一个点,加入有d天,那么要拆成d+1个点。

st与d(i,0)连弧,容量为相应城市的人数

d(i ,j) 与 d(i ,j+1)连弧,容量INF;

如果d(i,j) 到 d(k,j+1)有一班飞机,且费用小于等于我们枚举的费用,那么连弧,容量费飞机搭载人数。

最后用网络跑一次,判断是否满流即可。


下周各种考试啊。三门。一门都没复习,压力山大。。。。。该开始刷课本了,不然要跪了。 

Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu

[]   [Go Back]   [Status]  

Description

Download as PDF

Problem B
Buy one, get the rest free.
Time Limit: 3 seconds

"Whoa! It feels like I'm flying!"
Lrrr

It's year 2258, and the age of airplanes is coming to an end. Everyone is using teleporters now. In an effort to stay competitive, the last remaining air travel company, GetsJo, is offering the following deal to its customers. Instead of buying one plane ticket, you can rent a whole flight from A to B. Each flight can carry a certain number of people and costs a certain amount of money. If you do that, then you can rent all of the other flights of equal or lesser cost for free!

For example, if there are 4 flights with costs $10000, $25000, $30000 and $40000, and you rent the $30000 flight, then you get the $10000 and $25000 flights for free. The total cost to rent these 3 flights is $30000.

You want to organize a large programming competition and would like to invite all of the participants to city n, where the competition will be held. Being a nice person, you decide to pay for everyone's airplane tickets. Given the locations of the participants and the list of available flights between now and the day of the competition, what is the cost of renting enough flights to get all of the participants to city n in the next d days?

Input
The first line of input gives the number of cases, NN test cases follow. Each one starts with a line containing the number of cities (1<=n<=30), the number of days (1<=d<=10) until the competition and the number of flights (0<=m<=1000). m lines follow, each one containing 5 integers: uvcp and e (1<=u,v<=n, 1<=c<=100, 0<=e<d). This means that a flight that can carry c passengers and costs pdollars leaves city u on day e in the evening and arrives next day in the morning to city v. Day 0 is today, and all of the participants need to be in city n in the evening of day e. Finally, n integers (z1z2, ..., zn) follow, meaning that there are zi participants in city i on day 0 (0<=zi<=100). The maximum cost of a flight is 100000. There will never be two flights with the same uv and e values.

Output
For each test case, output one line containing "Case #x:" followed by the minimum required cost of flying all of the participants to city nbefore the end of day d. If no amount of money is enough, print "Impossible" instead.

Sample InputSample Output
2
5 4 5
1 5 100 30000 0
2 4 10 10000 0
2 4 10 10000 1
4 5 25 25000 2
2 5 100 40000 3
1 20 0 5 100
2 1 1
1 2 99 10400 0
100 0
Case #1: 30000
Case #2: Impossible


Problemsetter: Igor Naverniouk
Alternate solution: Yury Kholondyrev

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

#define INF 0x3FFFFFF
#define MAXN  500
#define MAXM  500010

struct edge
{
    int to,c,next;
};

edge e[MAXM];
int head[MAXN], en;
int n, m,d,vn;
int dis[MAXN];
int gap[MAXN];
int st, ed;

void add(int a, int b, int c)
{
    e[en].to=b;
    e[en].c=c;
    e[en].next=head[a];
    head[a]=en++;
    e[en].to=a;
    e[en].c=0;
    e[en].next=head[b];
    head[b]=en++;
}


int isap(int u,int flow)
{
    if(u==ed)
		return flow;
    int j,mindis=vn-1,t=flow,d;
    for(j=head[u];j!=-1;j=e[j].next)
	{
        int v=e[j].to,val=e[j].c;
        if(val>0)
		 {
            if(dis[v]+1==dis[u])
			 {
                if(t<e[j].c)
                    d=t;
				else
                    d=e[j].c;
                d=isap(v,d);
                e[j].c-=d,e[j^1].c+=d;
                t-=d;
                if(dis[st]>=vn)
                    return flow-t;
                if(t==0)
                    break;
            }
            if(dis[v]<mindis)
                mindis=dis[v];
        }
    }
    if(t==flow)
	{
        --gap[dis[u]];
        if (gap[dis[u]]==0)
            dis[st]=vn;
        dis[u]=mindis+1;
        ++gap[dis[u]];
    }
    return flow-t;
}

int sap()
{
    int ret=0;
    memset(gap,0,sizeof(gap));
    memset(dis,0,sizeof(dis));
    gap[0] = vn;
    while (dis[st]<vn)
        ret += isap(st, INF);
    return ret;
}

int c[500][500],w[500][500],cnt[50];

void build(int m)
{
    memset(head,-1,sizeof(head));en=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j) continue;
            for(int k=0;k<d;k++)
            {
                if(!c[i+n*k][j+n*(k+1)]) continue;
                if(w[i+n*k][j+n*(k+1)]<=m)
                    add(i+n*k,j+n*(k+1),c[i+n*k][j+n*(k+1)]);
            }
        }
    }
    st=0,ed=n*(d+1),vn=(d+1)*n+1;
    for(int i=1;i<=n;i++)
    {
        add(st,i,cnt[i]);
        for(int j=0;j<d;j++)
            add(i+j*n,i+(j+1)*n,INF);
    }
}

int main()
{
    int full,l,r;
    int t,u,v,cc,p,e;
    scanf("%d",&t);
    for(int ll=1;ll<=t;ll++)
    {
        scanf("%d%d%d",&n,&d,&m);
        l=0,r=0,full=0;
        memset(c,0,sizeof(c));
        memset(w,0,sizeof(w));
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d%d%d",&u,&v,&cc,&p,&e);
            c[u+e*n][v+(e+1)*n]=cc;
            w[u+e*n][v+(e+1)*n]=p;
            r=max(r,p);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&cnt[i]);
            full+=cnt[i];
        }
        int mid,ans=-1;
        while(l<=r)
        {
            mid=(l+r)>>1;
            build(mid);
            int flow=sap();
            if(flow==full)
            {
                r=mid-1;
                ans=mid;
            }
            else
                l=mid+1;
        }
        if(ans!=-1)
            printf("Case #%d: %d\n",ll,ans);
        else
            printf("Case #%d: Impossible\n",ll);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值