zoukankan      html  css  js  c++  java
  • BZOJ 3280: 小R的烦恼

    Description

    小R最近遇上了大麻烦,他的程序设计挂科了。于是他只好找程设老师求情。善良的程设老师答应不挂他,但是要
    求小R帮助他一起解决一个难题。问题是这样的,程设老师最近要进行一项邪恶的实验来证明P=NP,这个实验一共
    持续n天,第i天需要a[i]个研究生来给他搬砖。研究生毕竟也是人,所以雇佣研究生是需要钱的,机智的程设老师
    已经联系好了m所大学,第j所大学共有l[j]个研究生,同时雇佣这所大学的一个研究生需要p[j]元钱。本来程设老
    师满心欢喜的以为,这样捡最便宜的max{a[i]}个研究生雇来,就可以完成实验;结果没想到,由于他要求硕士生
    们每天工作25个小时不许吃饭睡觉上厕所喝水说话咳嗽打喷嚏呼吸空气,因此一天下来给他搬砖的所有研究生都会
    进入濒死状态。濒死状态的研究生,毫无疑问,就不能再进行工作了。但是机智的老师早早联系好了k家医院,第i
    家医院医治一个濒死的研究生需要d[i]天,并且需要q[i]元钱。现在,程设老师想要知道,最少花多少钱,能够在
    这n天中满足每天的需要呢?若无法满足,则请输出”impossible”。注意,由于程设老师良心大大的坏,所以他
    是可以不把濒死的研究生送去医院的!。

    Input

    本题包含多组数据;第一行是一个数T(T<=11),表示数据组数,以下T组数据。
    对于每一组数据,第一行三个数,n,m,k;
    以下一行n个数,表示a[1]…a[n]
    接着一行2m个数,表示l[1],p[1]…l[n],p[n]
    接着一行2k个数,表示d[1],q[1]…d[n],q[n]
    n,m,k<=50,其余数均小于等于100.

    Output

    对于每组数据以样例的格式输出一行,两个数分别表示第几组数据和最少钱数。

    Sample Input

    2

    3 2 1

    10 20 30

    40 90 15 100

    1 5

    3 2 1

    10 20 30

    40 90 15 100

    2 5

    Sample Output

    Case 1: 4650

    Case 2: impossible

    样例解释:

    买下90块钱的那40个研究生,另外再买10个100块钱的。这样,第一天用完的10个人全部送到医院,那么他们在第

    三天可以继续使用;同时,第二天和第三天都用新的研究生来弥补,这样一共需要花费4090 + 10100 + 5*10 =

    4650元。

    题解
    将每一天拆点,拆成活着的和死了的。
    从S向每个大学连边((l[i] , p[i]))
    每个大学向每天活着的连((inf , 0)) 的边。
    第i天会死去(a[i]) 个人,从S向每一天死去的人连((a[i] , 0)) 的边
    活着的人向T连((a[i] , 0)) 的边。
    死去的人可以留着明天再救((inf , 0)) 也可以现在救((inf , q[i])) 注意是连向i+d天。

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<set>
    #include<map>
    using namespace std;
    const int N = 666 , inf = 1e8;
    inline int read()
    {
        register int x = 0 , f = 0; register char c = getchar();
        while(c < '0' || c > '9') f |= c == '-' , c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
        return f ? -x : x;
    }
    int n , m , k , S , T , cnt = 1;
    int a[N] , p[N] , c[N] , d[N] , q[N] , head[N] , f[N] , dis[N] , pre[N] , vis[N];
    struct edge{ int v , nex , c , val; } e[N*N*10];
    inline void add(int u , int v , int c , int val)
    {
    	e[++cnt].v = v; e[cnt].nex = head[u]; e[cnt].c = c; e[cnt].val = val; head[u] = cnt;
    	e[++cnt].v = u; e[cnt].nex = head[v]; e[cnt].c = 0; e[cnt].val = -val; head[v] = cnt;
    	return ;
    }
    
    queue<int> Q;
    bool spfa()
    {
    	for(int i = 1 ; i <= T ; ++i) dis[i] = inf , pre[i] = 0; f[S] = inf; dis[S] = 0; Q.push(S);
    	while(Q.size())
    	{
    		int x = Q.front(); Q.pop(); vis[x] = 0;
    		for(int i = head[x] , v; i ; i = e[i].nex)
    		{
    			v = e[i].v;
    			if(e[i].c && dis[v] > dis[x] + e[i].val)
    			{
    				dis[v] = dis[x] + e[i].val; f[v] = min(f[x] , e[i].c);
    				pre[v] = i; if(!vis[v]) vis[v] = 1 , Q.push(v);
    			}
    		}
    	}
    	return dis[T] != inf;
    }
    
    int calc(int &flow)
    {
    	int ans = 0; flow = 0;
    	while(spfa())
    	{
    		ans += f[T] * dis[T]; flow += f[T];
    		for(int t = T , i; t != S ; t = e[i^1].v) i = pre[t] , e[i].c -= f[T] , e[i^1].c += f[T];
    	}
    	return ans;
    }
    
    void solve(int Case)
    {
    	n = read(); m = read(); k = read(); S = n+n+m+1; T = S+1; int sum = 0 , x , y;
    	for(int i = 1 ; i <= T ; ++i) head[i] = 0; cnt = 1; 
    	for(int i = 1 ; i <= n ; ++i) x = read() , add(S , i+n , x , 0) , add(i , T , x , 0) , sum += x;
    	for(int i = 1 ; i <= m ; ++i) x = read() , y = read() , add(S , i+n+n , x , y);
    	for(int i = 1 ; i <= m ; ++i) for(int j = 1 ; j <= n ; ++j) add(i+n+n , j , inf , 0); 
    	for(int i = 1 ; i < n ; ++i) add(i+n , i+n+1 , inf , 0);
    	for(int i = 1 ; i <= k ; ++i)
    	{
    		x = read(); y = read();
    		for(int j = 1 ; j + x < n ; ++j) add(j+n , j+x+1 , inf , y);
    	}
    	int flow = 0;
    	int ans = calc(flow);
    	printf("Case %d: " , Case);
    	if(flow != sum) puts("impossible"); else cout << ans << '
    ';
    }
    
    int main()
    {
    	int T = read();
    	for(int i = 1 ; i <= T ; ++i) solve(i);
    	return 0;
    }
    /*
    2
    
    3 2 1
    
    10 20 30
    
    40 90 15 100
    
    1 5
    
    3 2 1
    
    10 20 30
    
    40 90 15 100
    
    2 5
    */
    
  • 相关阅读:
    2019.1.1-11 总结
    配置文件的选择
    2019.1.1-5 总结
    shell 脚本
    2017- 感谢自己
    debug和release版本的区别
    linux 下一些命令
    Python中getopt()函数的使用
    开发环境的一些基本认识
    Leetcode 49. Group Anagrams
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12334293.html
Copyright © 2011-2022 走看看