ZOJ Problem Set - 3229 Shoot the Bullet 【有上下界网络流+流量输出】

时间:2022-04-18 13:37:17

题目:

problemId=3442" target="_blank">ZOJ Problem Set - 3229 Shoot the Bullet

分类:有源有汇有上下界网络流

题意:有 n 天和 m 个girls,然后每天给一部分girls拍照,每一个girls 有拍照的下限。即最少要拍这么多张。然后每天有k个女孩拍照,摄影师最多能够拍num张,然后 k 个女该每天拍照数量值有上下限,然后问你有没有满足这样条件的给女孩拍照的最慷慨案。然后依照输入输出每天给女孩拍照的张数。

做这道题目推荐先做:这儿

分析:首先它让你推断能不能满足条件。

依照题目给出的条件非常easy建图:

s ---> 天数,

天数  ---->  girls

girls  ----> t

(流量都为当前的上界减去下界)

这种话就建图成功了,可是这样不能推断。我们在加一条边 t -----> s,流量无穷

这种话原图编程一个循环图。即前面推荐的题目。依照那样的方法建图,然后求一次最大流看看是否满流。

然后增加满流的话。就能够考虑第二个问题了。每天给女孩拍照的最大的张数?

这样我们能够删去 t ---->  s 得边,然后求一次 s 到 t 的最大流。

然后依照题目要求输出流量就ok。

PS:伤在了英语上,没有读懂题目,然后错了无数次,最后最终懂了,坑题目。

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#define Del(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1550;
struct Node
{
int from,to,cap,flow;
};
vector<int> v[N];
vector<Node> e;
int vis[N]; //构建层次图
int cur[N];
void add_Node(int from,int to,int cap)
{
e.push_back((Node){from,to,cap,0});
e.push_back((Node){to,from,0,0});
int tmp=e.size();
v[from].push_back(tmp-2);
v[to].push_back(tmp-1);
}
bool bfs(int s,int t)
{
Del(vis,-1);
queue<int> q;
q.push(s);
vis[s] = 0;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=0;i<v[x].size();i++)
{
Node tmp = e[v[x][i]];
if(vis[tmp.to]<0 && tmp.cap>tmp.flow) //第二个条件保证
{
vis[tmp.to]=vis[x]+1;
q.push(tmp.to);
}
}
}
if(vis[t]>0)
return true;
return false;
}
int dfs(int o,int f,int t)
{
if(o==t || f==0) //优化
return f;
int a = 0,ans=0;
for(int &i=cur[o];i<v[o].size();i++) //注意前面 ’&‘,非常重要的优化
{
Node &tmp = e[v[o][i]];
if(vis[tmp.to]==(vis[o]+1) && (a = dfs(tmp.to,min(f,tmp.cap-tmp.flow),t))>0)
{
tmp.flow+=a;
e[v[o][i]^1].flow-=a; //存图方式
ans+=a;
f-=a;
if(f==0) //注意优化
break;
}
}
return ans; //优化
}
int dinci(int s,int t)
{
int ans=0;
while(bfs(s,t))
{
Del(cur,0);
int tm=dfs(s,inf,t);
ans+=tm;
}
return ans;
}
void MP_clear(int n)
{
for(int i=0;i<=n;i++)
v[i].clear();
e.clear();
}
int come[N],to[N];
int flow[400][N];
vector<pair<int ,int> > pp;
int main()
{
//freopen("Input.txt","r",stdin);
int n,m;
while(~scanf("%d%d",&n,&m))
{
Del(come,0);
Del(to,0);
Del(flow,0);
int s=n+m,t = s+1;
for(int i=0;i<m;i++)
{
int x;
scanf("%d",&x);
come[n+i]+=x;
to[t]+=x;
add_Node(n+i,t,inf);
}
for(int i=0;i<n;i++)
{
int cas,num;
scanf("%d%d",&cas,&num);
add_Node(s,i,num);
for(int j=0;j<cas;j++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
pair<int,int> ts(i,x);
pp.push_back(ts);
flow[i][x]+=y;
come[i]+=y;
to[n+x]+=y;
add_Node(i,n+x,z-y); //SB
}
}
add_Node(t,s,inf); //
int ss=t+1,tt=ss+1;
int count=0;
for(int i=0;i<=t;i++)
{
int cha = come[i]-to[i];
if(cha<0)
{
count+=-cha;
add_Node(ss,i,-cha);
}
if(cha>0)
add_Node(i,tt,cha);
}
int ans = dinci(ss,tt);
if(ans != count)
puts("-1");
else
{
//add_Node(t,s,0);
printf("%d\n",dinci(s,t)); //SB
for(int i=0;i<e.size();i++)
{
Node f = e[i];
if(i%2==0 && f.from<n){
flow[f.from][f.to-n]+=f.flow;
//printf("%d %d %d %d\n",f.from,f.to,f.cap,f.flow);
}
}
for(int i=0;i<pp.size();i++)
{
printf("%d\n",flow[pp[i].first][pp[i].second]);
}
}
printf("\n");
MP_clear(tt);
pp.clear();
}
return 0;
}