Alice's Chance poj 1698

刚开始我是则这样构图的
1.源点到1-7天的天数为最大的周数
2.每天与其对应的演电影的时间连接,容量为其周数
3.把每部电源的所有演出时间点再汇聚到一个节点(容量为inf),再把这个节点
与汇点连边,容量为该部电源其所需天数。

这样构图,一直wa, 早上起来才想到,没有考虑时间先后顺序。
如这组测试数据
3
3
1 1 1 1 1 1 1 105 15
1 1 1 1 1 1 1 14 2
1 1 1 1 1 1 1 7 20
正确的构图应该这样, 把所有时间(那天可以演电影的对应一个点,最后得到一个时间的点集。
2
0 1 0 1 0 1 0 9 3
1.构造时间的点集合为
point = { day{ (week - 1) * 7 + j), week <= 9, j <= 7)
2.源点到每个电影的容量为其要出演天数
3.时间点集合到汇点容量为1
4.判断最大流是否等于所有要出演的天数
*/

View Code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int mp[400][400];
int f[150][150];
int day[150],week[150];
int cnt;
int h[500];
int vh[500];
int num[500];

const int inf = 0x7f7f7f7f;
int ans;
int sum;
bool Find;

int max( int x, int y)
{
return x > y ? x : y;
}

void dfs( int x)
{
int hmin = cnt, i;
if( x == 1)
{
sum += ans;
Find = true;
return;
}
for( i = 0; i <= cnt; i++)
{
if( mp[x][i] > 0)
{
if( h[x] == h[i] + 1 )
{
if( mp[x][i] < ans )
ans = mp[x][i];
dfs( i );
if( h[0] >= cnt)
return;
if( Find )
break;
}
if( h[i] < hmin )
hmin = h[i];
}
}
if( Find )
{
mp[x][i] -= ans;
mp[i][x] += ans;
}
else
{

vh[h[x]]--;
if( vh[h[x]] == 0 )
h[0] = cnt;
h[x] = hmin + 1;
vh[h[x]]++;
}
}


int sap( )
{
memset(vh, 0, sizeof(vh));
memset(h, 0, sizeof(h));
vh[0] = cnt;
sum = 0;
while( h[0] < cnt)
{
ans = inf;
Find = false;
dfs( 0 );
}
return sum;
}


int main( )
{
int T,maxn, N, sumx;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
memset(mp, 0, sizeof(mp));
memset(f, 0, sizeof(f));
memset(num, 0, sizeof(num));
memset(day, 0, sizeof(day));
memset(week, 0,sizeof(week));
cnt = 360, maxn = 0, sumx = 0;//0,源点,1汇点
for( int i = 1; i <= N; i++)
{
for( int j = 1; j <= 7; j++)
{
scanf("%d",&f[i][j]);
}
scanf("%d%d",&day[i], &week[i]);
sumx += day[i];
}
//建图
for( int i = 1; i <= N; i++)
{
num[i] = cnt++;
mp[0][num[i]] = day[i];
for( int j = 1; j <= 7; j++)
{
if( f[i][j] )
{
for( int k = 0; k < week[i]; k++)
{
mp[num[i]][k * 7 + j + 1] = 1; //对应天数连线
mp[k * 7 + j + 1][1] = 1;
}
}
}
}
int cntx = sap( );
if( cntx == sumx )
puts("Yes");
else
puts("No");
}
return 0;
}


另外一种做法是二分图匹配。匈牙利算法。

两个集合X,Y, X集合是拍该电影所需的天数,拆点。

View Code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int mp[1011][400];
int f[30][30];
int week[30];
int day[30];
int color[1100];
int match[1100];
int N;

int find( int x )
{
for( int i = 1; i <= 360; i++)
{
if( !color[i] && mp[x][i] )
{
color[i] = 1;
if( match[i] == -1 || find( match[i] ))
{
match[i] = x;
return 1;
}
}

}
return 0;
}

int solve( )
{
int ans = 0;
memset(match,-1,sizeof(match));
for( int i = 1; i <= 1000; i++)
{
memset(color, 0, sizeof(color));
if( find(i))
ans++;
}
return ans;
}

int main( )
{
int T, t, sum, s, e;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
sum = 0;
s = e = 1;
memset(f, 0, sizeof(f));
memset(mp, 0, sizeof(mp));
for( int i = 1; i <= N; i++)
{
for( int j = 1; j <= 7; j++)
{
scanf("%d",&f[i][j]);
}
scanf("%d%d",&day[i], &week[i]);
sum += day[i];
}
for(int i = 1; i <= N; i++)
{
for( int j = 1; j <= 7; j++)
{
if( f[i][j] )
{
for( int l = s; l < s + day[i]; l++)
{
for( int k = 0; k < week[i]; k++)
mp[l][k * 7 + j] = 1;
}

}

}
s += day[i];
}
if( solve( ) == sum)
puts("Yes");
else
puts("No");
}
return 0;
}

 

Y集合是其对应的演电影的日子。

求其最大二分图匹配。



posted on 2012-03-24 09:24  more think, more gains  阅读(166)  评论(0编辑  收藏  举报

导航