bzoj1221 [HNOI2001]軟件開發 & bzoj3280 小R的煩惱

bzoj1221 [HNOI2001]軟件開發 & bzoj3280 小R的煩惱

bzoj1221 [HNOI2001]軟件開發

Description
某軟件公司正在規劃一項n天的軟件開發計劃,根據開發計劃第i天需要ni個軟件開發人員,爲了提高軟件開發人員的效率,公司給軟件人員提供了很多的服務,其中一項服務就是要爲每個開發人員每天提供一塊消毒毛巾,這種消毒毛巾使用一天後必須再做消毒處理後才能使用。消毒方式有兩種,A種方式的消毒需要a天時間,B種方式的消毒需要b天(b>a),A種消毒方式的費用爲每塊毛巾fA, B種消毒方式的費用爲每塊毛巾fB,而買一塊新毛巾的費用爲f(新毛巾是已消毒的,當天可以使用);而且f>fA>fB。公司經理正在規劃在這n天中,每天買多少塊新毛巾、每天送多少塊毛巾進行A種消毒和每天送多少塊毛巾進行B種消毒。當然,公司經理希望費用最低。你的任務就是:爲該軟件公司計劃每天買多少塊毛巾、每天多少塊毛巾進行A種消毒和多少毛巾進行B種消毒,使公司在這項n天的軟件開發中,提供毛巾服務的總費用最低。

Input
第1行爲n,a,b,f,fA,fB. 第2行爲n1,n2,……,nn. (注:1≤f,fA,fB≤60,1≤n≤1000)

Output
最少費用

Sample Input
4 1 2 3 2 1
8 2 1 6

Sample Output
38

bzoj3280 小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]

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

HINT
樣例解釋:買下90塊錢的那40個研究生,另外再買10個100塊錢的。這樣,第一天用完的10個人全部送到醫院,那麼他們在第三天可以繼續使用;同時,第二天和第三天都用新的研究生來彌補,這樣一共需要花費40*90 + 10*100 + 5*10 = 4650元。

數據規模:
對於30%的數據中的每組數據,
滿足n<=5,m,k<=2,其餘數均小於等於100或者
n<=10,m,k<=10,其餘數均小於等於20.
對於100%的數據
n,m,k<=50,其餘數均小於等於100.

爲什麼把這兩題放在一起呢?因爲他們很像啊.. 強行解釋自己不想寫多一篇博客

好吧其實真的很像,特別是這個構圖非常經典.. 那麼我就以1221爲例吧.. 因爲兩個構圖基本相同..

首先定義2*n個點,這2*n個點我把它分成兩類,每一類都有n個點..
X類點中第i個點表示第i天有多少餐巾用過,需要清洗,用當天可以用髒的餐巾數限制(st,i,a[i],0)
Y類點中第i個點表示第i天所擁有的乾淨餐巾數,用當天可以用髒的餐巾數限制(i+n,ed,a[i],0)
那麼第i天的乾淨餐巾可以留到i+1天使用(i+n,i+n+1,inf,0)
我可以第一天買我接下來所有天所需要買的乾淨餐巾(st,1+n,inf,f)
然後第i天用髒的餐巾經過洗滌可以在i+aa+1天以後使用(i,i+aa+1+n,inf,fa)
當然第i天用髒的餐巾經過洗滌也可以在i+bb+1天使用(i,i+bb+1+n,fb)

就是這麼構圖.. 我覺得我講的還是比較清晰的吧.. 不好的請老司機來指點..

我不會告訴你當初1221是抄題解的.. 什麼也不會啊 那麼3280也是同樣的構圖方法..

code
只有3280的.. 你問我爲什麼?我上面不是說了嘛..

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
using namespace std;
const int Maxn = 110;
const int inf = 0x7fffffff;
struct node {
    int x, y, next, c, d, opp;
}a[Maxn*Maxn*10]; int first[Maxn], len;
int _min ( int x, int y ){ return x < y ? x : y; }
void ins ( int x, int y, int c, int d ){
    len ++; int k1 = len;
    a[len].x = x; a[len].y = y; a[len].c = c; a[len].d = d;
    a[len].next = first[x]; first[x] = len;
    len ++; int k2 = len;
    a[len].x = y; a[len].y = x; a[len].c = 0; a[len].d = -d;
    a[len].next = first[y]; first[y] = len;
    a[k1].opp = k2;
    a[k2].opp = k1;
}
int st, ed, sc;
int n, m, K;
int dis[Maxn], pre[Maxn];
bool mark[Maxn];
bool bfs (){
    queue <int> q;
    memset ( pre, -1, sizeof (pre) );
    memset ( dis, 63, sizeof (dis) );
    memset ( mark, false, sizeof (mark) );
    q.push (st); dis[st] = 0; mark[st] = true;
    while ( !q.empty () ){
        int x = q.front (); q.pop ();
        for ( int k = first[x]; k; k = a[k].next ){
            int y = a[k].y;
            if ( dis[y] > dis[x]+a[k].d && a[k].c > 0 ){
                dis[y] = dis[x]+a[k].d;
                pre[y] = k;
                if ( mark[y] == false ){
                    mark[y] = true;
                    q.push (y);
                }
            }
        }
        mark[x] = false;
    } 
    return pre[ed] > 0;
}
int dfs ( int x, int flow ){
    mark[x] = true;
    if ( x == ed ) return flow;
    int delta = 0;
    for ( int k = first[x]; k; k = a[k].next ){
        int y = a[k].y;
        if ( dis[y] == dis[x]+a[k].d && a[k].c > 0 && flow-delta > 0 && mark[y] == false ){
            int minf = dfs ( y, _min ( a[k].c, flow-delta ) );
            sc += minf*a[k].d;
            delta += minf;
            a[k].c -= minf;
            a[a[k].opp].c += minf;
        }
    }
    return delta;
}
int main (){
    int i, j, k, T, Ti;
    Ti = 0;
    scanf ( "%d", &T );
    while ( T -- ){
        scanf ( "%d%d%d", &n, &m, &K );
        len = 0; memset ( first, 0, sizeof (first) );
        st = 0; ed = 2*n+1;
        int sum = 0;
        for ( i = 1; i <= n; i ++ ){
            int x;
            scanf ( "%d", &x );
            ins ( st, i, x, 0 );
            ins ( i+n, ed, x, 0 );
            sum += x;
        }
        for ( i = 1; i <= m; i ++ ){
            int x, y;
            scanf ( "%d%d", &x, &y );
            ins ( st, 1+n, x, y );
        }
        for ( i = 1; i < n; i ++ ) ins ( i+n, i+n+1, inf, 0 );
        for ( i = 1; i <= K; i ++ ){
            int x, y;
            scanf ( "%d%d", &x, &y );
            for ( j = 1; j <= n-x-1; j ++ ){
                ins ( j, j+x+1+n, inf, y );
            }
        }
        int ans = 0;
        sc = 0;
        while ( bfs () ){
            mark[ed] = true;
            while ( mark[ed] ){
                memset ( mark, false, sizeof (mark) );
                ans += dfs ( st, inf );
            } 
        }
        printf ( "Case %d: ", ++Ti );
        if ( ans != sum ) printf ( "impossible\n" );
        else printf ( "%d\n", sc );
    }
    return 0;
}

啊啊啊我漏了個換行符讓我整整等了1min的評測啊.. bzoj評測差評..

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章