2011-0040
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
= 题目大意 =
有N个小孩,每个小孩知道若干条信息,现在所有小孩要向大家分享最少Bi条最多Ci条信息,问编号为k的小孩最多能获知多少条信息。
= 解题报告 =
这题表示被坑了= =……原本以为是上下界网络流,搞半天才发现下界一点用都没有。注意到题目中有一句话,'''一条消息可以被不同的小孩分享多次''',于是在一个最大解的情况下即使有小孩没有分享完下界,他随便挑几条分享都不会影响题目的结果,于是下界就被去除了。
于是题目就变成了一个比较简单的网络流模型,图左边放N个小孩,右边放若干条信息,每个小孩向信息连一条边,流量随便即可,源点向小孩连一条流量是他共享消息数目的上界,每条消息向汇点连一条流量为1的下界,然后网络流即可。注意到询问的K号小孩自己的消息是肯定知道的,所以将源点连向K号小孩的边特殊处理一下设置成无限大,这样就可以保证K号小孩知道自己的全部消息,该题解决。
= 题目代码 =
{{{
#include<cstdio>
#include<cstring>
#include<map>
#define MAXN 10005
#define oo 999999999
using namespace std;
int S,E,n,m,i,j,totxx,x,bh;
map<int,int> DY;
struct ChiType{
int a,b,c,d[15];
}Chi[MAXN];
struct Dinic{
struct EdgeType{
int x,y,c;
EdgeType *next,*back;
}Edge[MAXN*20],*Gr[MAXN],*Cur[MAXN];
int lv[MAXN],e,head,tail,que[MAXN*10],x,path[MAXN],p,i,min,mink,ans,k;
int addedge(int x,int y,int c){
Edge[++e].x=x;
Edge[e].y=y;
Edge[e].c=c;
Edge[e].next=Gr[x];
Gr[x]=&Edge[e];
Edge[e].back=&Edge[e+1];
Edge[++e].x=y;
Edge[e].y=x;
Edge[e].c=0;
Edge[e].next=Gr[y];
Gr[y]=&Edge[e];
Edge[e].back=&Edge[e-1];
return 0;
}
int clear(){
e=0;
memset(Gr,0,sizeof(Gr));
memset(path,0,sizeof(path));
memset(Edge,0,sizeof(Edge));
return 0;
}
int find(){
memset(que,0,sizeof(que));
head=0; tail=1; que[tail]=S;
memset(lv,255,sizeof(lv));
lv[S]=0;
do{
head++;
x=que[head];
for(EdgeType *t=Gr[x];t;t=t->next){
if(lv[t->y]==-1&&t->c>0){
tail++;
que[tail]=t->y;
lv[t->y]=lv[x]+1;
if(t->y==E)return 1;
}
}
}while(head<=tail);
return 0;
}
int flow(){
ans=0;
while(find()){
path[0]=0; p=0;
for(i=S;i<=E;i++)
Cur[i]=Gr[i];
do{
x=path[p];
if(x==E){
min=oo;
for(i=0;i<=p-1;i++)
if(Cur[path[i]]->c<min){
min=Cur[path[i]]->c;
mink=i;
}
ans+=min;
for(i=0;i<=p-1;i++){
Cur[path[i]]->c-=min;
Cur[path[i]]->back->c+=min;
}
p=mink; continue;
}
for(;Cur[x];Cur[x]=Cur[x]->next){
k=Cur[x]->y;
if(Cur[x]->c>0&&lv[x]+1==lv[k]){
path[++p]=k;
break;
}
}
if(!Cur[x]){
p--;
lv[x]=-1;
}
}while(p!=-1);
}
return ans;
}
}Network;
int main(){
while(scanf("%d",&n)!=EOF){
Network.clear();
DY.clear();
for(i=1;i<=n;i++){
scanf("%d%d%d",&Chi[i].a,&Chi[i].b,&Chi[i].c);
for(j=1;j<=Chi[i].a;j++){
scanf("%d",&x);
if (DY.find(x)==DY.end()){
totxx++;
DY[x]=totxx;
bh=totxx;
}else bh=DY[x];
Chi[i].d[j]=bh;
}
}
scanf("%d",&m);
S=0; E=n+totxx+1;
for(i=1;i<=n;i++){
if(i==m)Network.addedge(S,i,oo);
else Network.addedge(S,i,Chi[i].c);
for(j=1;j<=Chi[i].a;j++)
Network.addedge(i,Chi[i].d[j]+n,oo);
}
for(i=1;i<=totxx;i++)
Network.addedge(i+n,E,1);
printf("%d\n",Network.flow());
}
}
}}}
Finished by Dai@NeverLand
题目大意
有N个小孩,每个小孩知道若干条信息,现在所有小孩要向大家分享最少Bi条最多Ci条信息,问编号为k的小孩最多能获知多少条信息。
解题报告
这题表示被坑了= =……原本以为是上下界网络流,搞半天才发现下界一点用都没有。注意到题目中有一句话,一条消息可以被不同的小孩分享多次,于是在一个最大解的情况下即使有小孩没有分享完下界,他随便挑几条分享都不会影响题目的结果,于是下界就被去除了。
于是题目就变成了一个比较简单的网络流模型,图左边放N个小孩,右边放若干条信息,每个小孩向信息连一条边,流量随便即可,源点向小孩连一条流量是他共享消息数目的上界,每条消息向汇点连一条流量为1的下界,然后网络流即可。注意到询问的K号小孩自己的消息是肯定知道的,所以将源点连向K号小孩的边特殊处理一下设置成无限大,这样就可以保证K号小孩知道自己的全部消息,该题解决。
题目代码
#include<cstdio>
#include<cstring>
#include<map>
#define MAXN 10005
#define oo 999999999
using namespace std;
int S,E,n,m,i,j,totxx,x,bh;
map<int,int> DY;
struct ChiType{
int a,b,c,d[15];
}Chi[MAXN];
struct Dinic{
struct EdgeType{
int x,y,c;
EdgeType *next,*back;
}Edge[MAXN*20],*Gr[MAXN],*Cur[MAXN];
int lv[MAXN],e,head,tail,que[MAXN*10],x,path[MAXN],p,i,min,mink,ans,k;
int addedge(int x,int y,int c){
Edge[++e].x=x;
Edge[e].y=y;
Edge[e].c=c;
Edge[e].next=Gr[x];
Gr[x]=&Edge[e];
Edge[e].back=&Edge[e+1];
Edge[++e].x=y;
Edge[e].y=x;
Edge[e].c=0;
Edge[e].next=Gr[y];
Gr[y]=&Edge[e];
Edge[e].back=&Edge[e-1];
return 0;
}
int clear(){
e=0;
memset(Gr,0,sizeof(Gr));
memset(path,0,sizeof(path));
memset(Edge,0,sizeof(Edge));
return 0;
}
int find(){
memset(que,0,sizeof(que));
head=0; tail=1; que[tail]=S;
memset(lv,255,sizeof(lv));
lv[S]=0;
do{
head++;
x=que[head];
for(EdgeType *t=Gr[x];t;t=t->next){
if(lv[t->y]==-1&&t->c>0){
tail++;
que[tail]=t->y;
lv[t->y]=lv[x]+1;
if(t->y==E)return 1;
}
}
}while(head<=tail);
return 0;
}
int flow(){
ans=0;
while(find()){
path[0]=0; p=0;
for(i=S;i<=E;i++)
Cur[i]=Gr[i];
do{
x=path[p];
if(x==E){
min=oo;
for(i=0;i<=p-1;i++)
if(Cur[path[i]]->c<min){
min=Cur[path[i]]->c;
mink=i;
}
ans+=min;
for(i=0;i<=p-1;i++){
Cur[path[i]]->c-=min;
Cur[path[i]]->back->c+=min;
}
p=mink; continue;
}
for(;Cur[x];Cur[x]=Cur[x]->next){
k=Cur[x]->y;
if(Cur[x]->c>0&&lv[x]+1==lv[k]){
path[++p]=k;
break;
}
}
if(!Cur[x]){
p--;
lv[x]=-1;
}
}while(p!=-1);
}
return ans;
}
}Network;
int main(){
while(scanf("%d",&n)!=EOF){
Network.clear();
DY.clear();
for(i=1;i<=n;i++){
scanf("%d%d%d",&Chi[i].a,&Chi[i].b,&Chi[i].c);
for(j=1;j<=Chi[i].a;j++){
scanf("%d",&x);
if (DY.find(x)==DY.end()){
totxx++;
DY[x]=totxx;
bh=totxx;
}else bh=DY[x];
Chi[i].d[j]=bh;
}
}
scanf("%d",&m);
S=0; E=n+totxx+1;
for(i=1;i<=n;i++){
if(i==m)Network.addedge(S,i,oo);
else Network.addedge(S,i,Chi[i].c);
for(j=1;j<=Chi[i].a;j++)
Network.addedge(i,Chi[i].d[j]+n,oo);
}
for(i=1;i<=totxx;i++)
Network.addedge(i+n,E,1);
printf("%d\n",Network.flow());
}
}
Finished by Dai@NeverLand