您的位置:首页 > 其它

BZOJ 2330: [SCOI2011]糖果

2017-01-12 09:26 218 查看
第一次写差分约束,收获很多,首先我们表示一个人一定要比另一个人少只需要从这个人向另一个人连一条边权为1的边,小于等于就连一条边权为0的边,等于就连两条,但是为什么求最小值却要求最大流呢?因为我们可以想象一下我们规定的这些限制条件在最小流时可能并不能得到满足(模拟一下便知)只有当求最大流时能满足所有限制条件得到一组可行解,因为我们没连没有用的其他边,所以这也是满足所有条件的最小值,然后题目中还有一个条件就是每个小朋友都必须分到糖果,我们只需要新建一个超级源点,让它向每个点都连一个1就可以了。

#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
struct bian
{
int l,r,v;
}a[1000000];
int fir[1000000];
int nex[1000000];
int tot=1;
int dis[1000000];
bool pd[1000000];
int sum[1000000];
void add_edge(int l,int r,int v)
{
a[++tot].l=l;
a[tot].r=r;
a[tot].v=v;
nex[tot]=fir[l];
fir[l]=tot;
}
queue<int> dui;
int n;
bool spfa()
{
memset(dis,0xef,sizeof(dis));
dis[0]=0;
dui.push(0);
pd[0]=true;
while(!dui.empty())
{
int u=dui.front();
dui.pop();
pd[u]=false;
for(int o=fir[u];o;o=nex[o])
{
if(dis[u]+a[o].v>dis[a[o].r])
{
dis[a[o].r]=dis[u]+a[o].v;
sum[a[o].r]=sum[u]+1;
if(sum[a[o].r]>n+1) return false;
if(!pd[a[o].r])
{
pd[a[o].r]=true;
dui.push(a[o].r);
}
}
}

}
return true;
}
int main()
{
int m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int p,x,y;
scanf("%d%d%d",&p,&x,&y);
if(p==1)
{
add_edge(x,y,0);
add_edge(y,x,0);
}
if(p==2) add_edge(x,y,1);
if(p==3) add_edge(y,x,0);
if(p==4) add_edge(y,x,1);
if(p==5) add_edge(x,y,0);
}
for(int i=n;i>=1;i--) add_edge(0,i,1);
if(!spfa()) cout<<-1;
else
{
long long ans=0;
for(int i=1;i<=n;i++) ans+=dis[i];
cout<<ans;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  差分约束