您的位置:首页 > 其它

POJ 1698 构图+最大流

2012-06-19 20:59 316 查看
题目链接: http://poj.org/problem?id=1698

题目大意:

  man需要一个安排表参见演出,有n(n<=20)场,每场指定了必须表演的天数Di,和截止的周数Week_i,还指定了必须星期几表演,要求man一天最多参加一场,问能否有一个安排使得满足要求,有输出Yes,否则输出No;

分析:

  开始自己想了个392个点的构图,后来看了题解,发现我多了一层(我拆了点,其实没有必要)……

  源ST分别向n个场次连边(1……n),边容量为各场指定的天数Di, 各场(1……n)分别作为一个节点,向指定的星期连边(注意从第一周到第Week_i的都要),容量为1(只要大于0的整数实际都可以), 然后每天 (n+1……n+(Week*7))分别向汇点ED连边,容量为1;

  求一次最大流,看maxflow是否等于sum{ Di };

  最多372个点,果断上Edmond_Karp!

代码:

poj1698

/*1698    Accepted    1328K    141MS    G++    2140B    2012-06-19 20:42:23*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

#define mpair make_pair
#define pii pair<int,int>
#define MM(a,b) memset(a,b,sizeof(a));
typedef long long lld;
typedef unsigned long long u64;
template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}
#define maxn 390
const int inf= 2100000000;

int n;
int ST, ED;
int g[maxn][maxn];

int Read(){
int i, j, k, t, D, W, sum= 0, week= 0;
scanf("%d", &n);
ST= 0;
MM( g, 0 );
vector<int> a;
for(i=1;i<=n;++i){
a.clear();
for(j=1;j<=7;++j){
scanf("%d", &t);
if( 1==t ) a.push_back( j );
}
scanf("%d%d", &D, &W);
g[ST][i]= D;
sum+= D;
up_max( week, W );
for(j=1;j<=W;++j)
for(k=0;k<a.size();++k)
g[i][ n+(j-1)*7+a[k] ]= 1; ///!!!
}
ED= n + 7*week + 1;
for(i=n+1;i<=n+7*week;++i) g[i][ED]= 1;
return sum;
}

bool vis[maxn];
int que[maxn], pre[maxn];
bool bfs(){
fill( vis, vis+1+ED, 0 );
int head= 0, tail= 0;
que[tail++]= ST;
vis[ST]= 1;
while( head<tail ){
int u= que[head++];
for(int v=1;v<=ED;++v){
if( g[u][v]>0 && !vis[v] ){
pre[v]= u;
if( v==ED ) return 1;
que[tail++]= v;
vis[v]= 1;
}
}
}
return 0;
}

int Edmond_karp(){
int ret= 0;
while( bfs() ){
int t= inf;
for(int i=ED;i!=ST;i=pre[i])
up_min( t, g[pre[i]][i] );
ret+= t;
for(int i=ED;i!=ST;i=pre[i]){
g[pre[i]][i]-= t;
g[i][pre[i]]+= t;
}
}
return ret;
}

int main()
{
//freopen("poj1689.in","r",stdin);
int Cas;
cin>>Cas;
while( Cas-- ){
int sum= Read();
int ret= Edmond_karp();
if( sum==ret ) puts("Yes");
else puts("No");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: