2661: [BeiJing wc2012]连连看(拆点费用流)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2661

每个点拆成两个,可以消掉的连边,然后在二分图中做一次费用流即可。

代码(原始对偶算法):

#include 
#include 
#include 
#include 
#include 
 
using namespace std;
 
#define MAXN 1010
#define inf 0x7fffffff
#define MAXV 2010
 
struct edge {
    int t,f,c;
    edge *pair,*next;
    edge () {
        pair=next=NULL;
    }
} *head[MAXV];
 
void Add(int s,int t,int f,int c) {
    edge *p=new(edge);
    p->t=t,p->f=f,p->c=c,p->next=head[s];
    head[s]=p;
}
 
void AddEdge(int s,int t,int f,int c) {
    Add(s,t,f,c),Add(t,s,0,-c);
    head[s]->pair=head[t],head[t]->pair=head[s];
}
 
int dist[MAXV],V,S,T,maxflow=0,cost=0;
bool f[MAXV];
queueQ;
 
bool spfa() {
    for (int i=0;i++next) if (p->f&&dist[p->t]c) {
            dist[p->t]=dist[v]+p->c,Q.push(p->t),f[p->t]=true;
        }
    }
    return dist[T]>-inf;
}
 
int aug(int v,int flow) {
    if (v==T) {
        cost+=dist[T]*flow,maxflow+=flow;
        return flow;
    }
    int rec=0;
    f[v]=false;
    for (edge *p=head[v];p;p=p->next) if (p->f&&f[p->t]&&dist[p->t]==dist[v]+p->c) {
        int ret=aug(p->t,min(flow-rec,p->f));
        p->f-=ret,p->pair->f+=ret;
        if ((rec+=ret)==flow) return flow;
    }
    return rec;
}
 
void costflow() {
    while (spfa()) {
        do {
            memset(f,true,sizeof(f));
        } while (aug(S,inf));
    }
}
 
int a,b,v[MAXN][2];
 
int gcd(int x,int y) {
    if (!y) return x;
    return gcd(y,x%y);
}
 
bool check(int x,int y) {
    if (x>1,cost>>1);
    return 0;
}

你可能感兴趣的:(2661: [BeiJing wc2012]连连看(拆点费用流))