您的位置:首页 > 其它

bzoj2879 [Noi2012]美食节

2013-04-19 22:04 295 查看
这个题一眼看出是修车,但数据范围有点卡,我傻傻地以为写个zkw就万事大吉了,结果发现zkw还没有spfa跑的快......

这个题的关键是动态加边,就是每次找到已经增广到最新的点的厨师给他加一个新点,这样一共需要增广P次,就可以跑出答案了。

View Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define maxn 100000
#define maxm 100000
#define inf 2147483647
using namespace std;
struct et
{
int s,t,val,cost,next;
}e[maxm];
int fir[maxn],dis[maxn],pre[maxn],q[maxm],t[200][200],now[maxn],cnt[maxn];
bool inque[maxn];
int n,m,tot,st,ed,sum,fare,k,ans;

bool find()
{
int head=0,tail=1;
for (int i=st;i<=ed;i++) dis[i]=inf;
q[1]=st; dis[st]=0; inque[st]=1;
while (head<tail)
{
int now=q[++head];
for (int j=fir[now];j;j=e[j].next)
{
int k=e[j].t;
if (e[j].val&&dis[now]+e[j].cost<dis[k])
{
dis[k]=dis[now]+e[j].cost;
pre[k]=j;
if (!inque[k]) q[++tail]=k,inque[k]=1;
}
}
inque[now]=0;
}
}

void add(int x,int y,int z,int w)
{
e[++tot].s=x; e[tot].t=y; e[tot].val=z; e[tot].cost=w; e[tot].next=fir[x]; fir[x]=tot;
e[++tot].s=y; e[tot].t=x; e[tot].val=0; e[tot].cost=-w; e[tot].next=fir[y]; fir[y]=tot;
}

void adjust()
{
for (int j=1;j<=m;j++)
if (e[now[j]].val==0) {
cnt[j]++;
now[j]=tot+1;
add(n+sum*(j-1)+cnt[j],ed,1,0);
for (int i=1;i<=n;i++) add(i,n+sum*(j-1)+cnt[j],1,t[i][j]*cnt[j]);
return ;
}
}

void fare_flow()
{
find();
fare+=dis[ed];
for (int j=pre[ed];j;j=pre[e[j].s]) e[j].val--,e[j^1].val++;
adjust();
}

int main()
{
freopen("delicacy.in","r",stdin);
freopen("delicacy.out","w",stdout);
scanf("%d%d",&n,&m);
tot=1;
int x;
st=0;
for (int i=1;i<=n;i++) {
scanf("%d",&x);
add(st,i,x,0);
sum+=x;
}
ed=m*sum+n+1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
scanf("%d",&t[i][j]);
add(i,n+(j-1)*sum+1,1,t[i][j]);
}
for (int i=1;i<=m;i++)
{
cnt[i]=1;
now[i]=tot+1;
add(n+(i-1)*sum+1,ed,1,0);
}
for (int i=sum;i>0;i--) fare_flow();
printf("%d\n",fare);
return 0;
}


常数大......
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: