最大权闭合图

最大权闭合图完美的解决了网络流中,对节点间>1的依赖关系。

 

hdu 5845 (二分+最大权闭合图)

#include <math.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <set>
#include <map>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <iostream>
#include <algorithm>
#define pb push_back
#define fi first
#define se second
#define icc(x) (1<<(x))
#define lcc(x) (1ll<<(x))
#define lowbit(x) (x&-x)
#define debug(x) cout<<#x<<"="<<x<<endl
#define rep(i,s,t) for(int i=s;i<t;++i)
#define per(i,s,t) for(int i=t-1;i>=s;--i)
#define mset(g, x) memset(g, x, sizeof(g))
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int ui;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> veci;
const int mod=(int)1e9+7,inf=0x3fffffff,rx[]={-1,0,1,0},ry[]={0,1,0,-1};
const ll INF=1ll<<60;
const db pi=acos(-1),eps=1e-8;

template<class T> void rd(T &res){
    res = 0; int ch,sign=0;
    while( (ch=getchar())!='-' && !(ch>='0'&&ch<='9'));
    if(ch == '-') sign = 1; else res = ch-'0';
    while((ch=getchar())>='0'&&ch<='9') res = (res<<3)+(res<<1)+ch-'0';
    res = sign?-res:res;
}
template<class T>void rec_pt(T x){
    if(!x)return;
    rec_pt(x/10);
    putchar(x%10^48);
}
template<class T>void pt(T x){
    if(x<0) putchar('-'),x=-x;
    if(!x)putchar('0');
    else rec_pt(x);
}
template<class T>inline void ptn(T x){ pt(x),putchar('\n'); }
template<class T>inline void Max(T &a,T b){ if(b>a)a=b; }
template<class T>inline void Min(T &a,T b){ if(b<a)a=b; }
template<class T>inline T mgcd(T b,T d){ return b?mgcd(d%b,b):d; }//gcd模板,传入的参数必须是用一类型
//-------------------------------主代码--------------------------------------//

//网络流SAP模板,复杂度O(N^2*M)
//使用前调用init(源点,汇点,图中点的个数),然后调用add_edge()加边
//调用getflow得出最大流
#define N 404
#define M 2*N*N



struct Max_Flow
{
    struct node
    {
        int to,w,next;
    }edge[M];
    
    int s,t;
    int nn;
    int cnt,pre[N];
    int lv[N],gap[N];
    
    void init(int ss,int tt,int num)
    {
        s=ss;
        t=tt;
        nn = num;//
        cnt=0;
        memset(pre,-1,sizeof(pre));
    }
    void add_edge(int u,int v,int w)//同时建两条边
    {
        edge[cnt].to=v;
        edge[cnt].w=w;
        edge[cnt].next=pre[u];
        pre[u]=cnt++;
        
        edge[cnt].to=u;
        edge[cnt].w=0;
        edge[cnt].next=pre[v];
        pre[v]=cnt++;
    }
    
    int sdfs(int k,int w)
    {
        if(k==t) return w;
        int f=0;
        int mi=nn-1;
        for(int p=pre[k];p!=-1;p=edge[p].next)
        {
            int v=edge[p].to,tw=edge[p].w;
            if(tw!=0)
            {
                if(lv[k]==lv[v]+1)
                {
                    int tmp=sdfs(v,min(tw,w-f));
                    f+=tmp;
                    edge[p].w-=tmp;
                    edge[p^1].w+=tmp;
                    if(f==w||lv[s]==nn) break;
                }
                if(lv[v]<mi) mi=lv[v];
            }
        }
        if(f==0)
        {
            gap[lv[k]]--;
            if( gap[ lv[k] ]==0 )
            {
                lv[s]=nn;
            }
            lv[k]=mi+1;
            gap[lv[k]]++;
        }
        return f;
    }
    
    int getflow()
    {
        int sum=0;
        memset(lv,0,sizeof(lv));
        memset(gap,0,sizeof(gap));
        gap[0]=nn;
        while(lv[s]<nn)
        {
            sum+=sdfs(s,inf);
        }
        return sum;
    }
    
}ff;

int pay[202],pro[202],costtime[202];
int mat[202][202];
int mark[202];

int main()
{
    int T;
    rd(T);
    int tt = 1;
    while (T--) {
        int n,m,L;
        rd(n),rd(m),rd(L);
        int b = 0,d = 1e9+1;
        rep(i, 1, n+1){
            rd(pay[i]); rd(costtime[i]);
        }
        mset(mat, 0);
        rep(i, 1, m+1){
            rd(pro[i]);
            int k;
            rd(k);
            rep(j, 0, k){
                int tmp;
                rd(tmp);
                mat[i][tmp] = 1;
            }
        }
        int sum = 0;
        int ans = 0;
        while(b < d){
            int mid = (b+d)/2;
            mset(mark, 0);
            ff.init(0, n+m+1, n+m+2);
            rep(i, 1, n+1){
                if(costtime[i]<=mid){
                    ff.add_edge(m+i, n+m+1, pay[i]);
                    mark[i] = 1;
                }
            }
            sum = 0;
            rep(i, 1, m+1){
                int flag = 0;
                rep(j, 1, n+1){
                    if(mat[i][j]==1 && mark[j]==0){
                        flag = 1;
                        break;
                    }
                }
                if(flag == 0)
                {
                    sum += pro[i];
                    ff.add_edge(0, i, pro[i]);
                    rep(j, 1, n+1){
                        if(mat[i][j] == 1){
                            ff.add_edge(i, m+j, inf);
                        }
                    }
                }
            }
            int flow = ff.getflow();
            sum -= flow;
            if(sum>=L) d = mid,ans = sum;
            else b = mid+1;
        }
        
        printf("Case #%d: ",tt++);
        if(b >= 1e9+1){
            printf("impossible\n");
        }else
        {
            pt(b); putchar(' '); ptn(ans);
        }
        
    }
    return 0;
}

 

posted @ 2016-08-26 10:33  chenhuan001  阅读(164)  评论(0编辑  收藏  举报