POJ 1698 Alice's Chance(最大流,构图题)
今天早上还算顺利,过了两题不是很水的题目,这题Alice就是一个构图题,刚开始感觉思路是有的,可能交了一边是WA就郁闷了!刚开始的思路是
“ 把源点和周一到周日相连,权值是全部电影中需要的星期最长的,如第一个例题是4,
然后 日期1到7和电影从8开始有关的相连,权值是电影需要的星期数,最后是电影到汇点的权值是需要的天数。”
话说某大神要是看到这个思想,希望提出不足之处,非常感谢!
发现不行的,之后改成了把每个电影需要的星期数都拆开,变成一条线的权值设为1,这样每个星期中的某一天只能被一部电影占据,源点直接连接到电影,权值为需要的天数,之后将日期和汇点相连,比如有一部电影需要4周,就需要有4*7=28个点和汇点相连!这样开了15000的数据,还能32MS,Dinic挺快的了!
构图题,Dinic用的还是之前的模板!没什么好讲的了!
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define maxn 16000
const int INF=0xffffff;
int f[25][9];
struct edge
{
int from,to,val,next;
}map[maxn];
int vis[maxn],que[maxn],dist[maxn],len;
void init() //初始化 切记
{
len=0;
memset(vis,-1,sizeof(vis));
}
void insert (int from,int to,int val)
{
map[len].from=from,map[len].to=to,map[len].val=val;
map[len].next=vis[from];
vis[from]=len++;
map[len].from=to,map[len].to=from,map[len].val=0;
map[len].next=vis[to];
vis[to]=len++;
}
int Dinic(int n,int s,int t)
{
int ans=0;
while(true)
{
int head,tail,id,i;
head=tail=0;
que[tail++]=s;
memset(dist,-1,sizeof(dist));
dist[s]=0;
while(head<tail)
{
id=vis[que[head++]];
while(id!=-1)
{
if(map[id].val>0&&dist[map[id].to]==-1)
{
dist[map[id].to]=dist[map[id].from]+1;
que[tail++]=map[id].to;
if(map[id].to==t)
{
head=tail;
break;
}
}
id=map[id].next;
}
}
if(dist[t]==-1)
break;
id=s,tail=0;
while(true)
{
if(id==t) //找到一条增广路
{
int flow=INF,fir;
for(i=0;i<tail;i++)
if(map[que[i]].val<flow)
{
fir=i;
flow=map[que[i]].val;
}
for(i=0;i<tail;i++)
map[que[i]].val-=flow,map[que[i]^1].val+=flow;
ans+=flow;
tail=fir;
id=map[que[fir]].from;
}
id=vis[id];
while(id!=-1)
{
if(map[id].val>0&&dist[map[id].from]+1==dist[map[id].to])
break;
id=map[id].next;
}
if(id!=-1)
{
que[tail++]=id;
id=map[id].to;
}
else
{
if(tail==0)
break;
dist[map[que[tail-1]].to]=-1;
id=map[que[--tail]].from;
}
}
}
return ans;
} //以上是纯模板 只要知道输入 Dinic 的三个int 是点数 起点 汇点
int main()
{
int n,i,j;
int t;
int sum;
int D,W,k;
int flag=0;
scanf("%d",&t);
while(t--)
{
memset(f,0,sizeof(f));
init();
flag=0;
sum=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
for(j=1;j<=7;j++)
scanf("%d",&f[i][j]);
scanf("%d%d",&D,&W);
insert(0,i,D); //源点和电影部数相连
sum+=D;
if(flag<W)
flag=W;
for(k=0;k<W;k++)
for(j=1;j<=7;j++)
if(f[i][j])
insert(i,7*k+j+n,1); //电影和各周中相应的天数相连,权值为1
}
int T=n+7*flag+1;
for(i=0;i<flag;i++) //将每个星期的周一到周日都和汇点相连
for(j=1;j<=7;j++)
insert(7*i+n+j,T,1);
int ans=Dinic(T+1,0,T);
if(sum==ans) //如果需要的天数满流就YES
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
我把代码折起来是希望看到思路的人自己回去敲一下!这样进步比较快!
浙公网安备 33010602011771号