joj 2453 candy 网络流建图的题
2013-08-16 19:03
218 查看
Problem D: Candy
As a teacher of a kindergarten, you have many things to do during a day, one of which is to allot candies to all children in your class. Today you have N candies for the coming M children. Each child likes different candy, and as a teacher who know them well, you can describe how the child i likes the candy j with a number Aji (Aji = 2 if the child i likes the candy j, or else Aji = 1).The child i feels happy while
( Cij = 1 if the child i get the candy j, or else Cij = 0). Now your task is to allot the candies in such a way that makes every child happy (of course except you, ^_^).
Input
The first line of the input contains a single integer T (1 <= T <= 10), representing the number of cases that follow.The first line of each case consists of two integers N and M (1 <= N <= 100000, 1 <= M <= 10), which are the number of candies and the number of children.
There are N lines following, the ith line containing M integers: Ai1, Ai2, Ai3, ..., AiM (1 <= Aij <= 2)
The last line of the case consists of M integers: B1, B2, B3, ..., BM (0 <= Bi <= 1000000000).
Output
For each case, if there is a way to make all children happy, display the word “Yes”. Otherwise, display the word “No”.Sample Input
2 4 3 1 2 1 2 1 1 1 1 2 1 2 2 3 2 2 1 1 1 2
Sample Output
Yes No
网络流,主要是建图
分配的时候肯定会优先给每个孩子分配喜欢的糖果,所以先只考虑Aij=2的孩子和糖果(i,j)。
如果Ai,j=2,那么把孩子i向糖果j连一条容量为1的边,再建立源点S,向每个孩子连一条容量为Bi/2的边(因为每个开心值为2的糖果只算1,所以孩子的B值也要先除以2),最后把每个糖果向汇点T连容量为1的边,做一次网络最大流。
假设S到孩子i的流量为fi,说明孩子i已经获得了fi*2点快乐值,还需要Bi-fi*2点,这时候f1+f2+..+fm是总共分出去的糖果数,那么还剩N-(f1+f2+..+fm)个糖果,如果这个数>=sigma(Bi-fi*2),即剩余的糖果数大于等于孩子还需要的总共快乐值,则有解,否则无解
PS:每个孩子平均能吃10000个糖,我真是无限ORZ
以下使用的是刘汝佳白书上的DINIC算法模板做的
#include<iostream> #include<algorithm> #include<cstring> #define size_num 100200 #include<vector> #include<queue> #define INF 1e8 using namespace std; int child[105]; struct Dinic { struct Edge{int from,to,cap,flow;}; vector<Edge> edges; //边表。edges[e]和edges[e+1]互为反向弧, //注意到e必须是偶数即是大的奇数与比他小的偶数互为反向边,即e与e^1互为反向边 vector<int> G[size_num]; //领接表,G[i][j]表示节点i的第j条边在e数组中的序号 void add_edge(int from,int to,int cap) { edges.push_back((Edge){from,to,cap,0});//加入正向边 edges.push_back((Edge){to,from,0,0});//加入反向边 int m=edges.size(); G[from].push_back(m-2);//存的是边的位子 G[to].push_back(m-1);//貌似有一种静态链表的感觉 } int s,t;//源点编号和汇点编号 bool vis[size_num];//bfs时使用 int d[size_num];//从起点到i的距离 int cur[size_num];//当前弧的下标 void init() { edges.clear(); for(int i=0;i<size_num;i++) G[i].clear(); } bool bfs() { memset(vis,0,sizeof(vis)); queue<int > q; q.push(s); d[s]=0; vis[s]=1; while(!q.empty()) { int x=q.front();q.pop(); for(int i=0;i<G[x].size();i++) { Edge&e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow) { vis[e.to]=1; d[e.to]=d[x]+1; q.push(e.to); } } } return vis[t]; } //dfs int dfs(int x,int a) { if (x==t||a==0) return a; int flow=0,f; for(int &i=cur[x];i<G[x].size();i++)//从上次考虑的弧 { Edge &e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0) { e.flow+=f;//增加正向的流量 edges[G[x][i]^1].flow-=f;//减少反向的流量 flow+=f; a-=f; if(a==0) break; } } return flow; } // int maxflow(int s,int t) { this->s=s;this->t=t; int flow=0; while(bfs()) { memset(cur,0,sizeof(cur)); flow+=dfs(s,INF); } return flow; } }solve; void read() { solve.init(); int n,m;//糖果数量和孩子的数量 cin>>n>>m; int s=0,t=1+m+n; //solve->n=t+1; //1->m表示孩子,m+1->m+n表示糖果 for(int i=1;i<=n;i++) { solve.add_edge(i+m,t,1); for(int j=1;j<=m;j++) { int temp; cin>>temp; if(temp==2) solve.add_edge(j,m+i,1); } } long long sum=0; for(int i=1;i<=m;i++) { cin>>child[i]; sum+=child[i]; solve.add_edge(s,i,child[i]/2); } int f=solve.maxflow(s,t); int yu=n-f; if(sum<=yu+f*2) cout<<"Yes\n"; else cout<<"No\n"; } int main() { int T;cin>>T; while(T--) read(); return 0; }
以下是不用vector的代码比较快0.5s上一个是3.07秒
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> const int maxn = 100055; const int maxm = 600005; const int inf = 0x3f3f3f3f; struct MaxFlow { int net[maxn], gap[maxn], dis[maxn], pre[maxn], cur[maxn]; int siz, n; std::queue <int> Q; struct EDGE { int v, cap, next; EDGE(){} EDGE(int a, int b, int c): v(a), cap(b), next(c){} }E[maxm<<1]; void init(int _n)//要传入节点数 { n = _n, siz = 0; memset(net, -1, sizeof(net)); } void add_edge(int u, int v, int cap)//加边操作 { E[siz] = EDGE(v, cap, net[u]); net[u] = siz++; E[siz] = EDGE(u, 0, net[v]); net[v] = siz++; } void bfs(int st)//广搜 { int u, v; for(int i = 0; i <= n; i++) dis[i] = n, gap[i] = 0; gap[0] = 1, dis[st] = 0; Q.push(st); while(!Q.empty()) { u = Q.front(); Q.pop(); for(int i = net[u]; i != -1; i = E[i].next) { v = E[i].v; if(!E[i^1].cap || dis[v] < n) continue; dis[v] = dis[u] + 1; gap[dis[v]]++; Q.push(v); } } } int isap(int st, int en)//st 是源点 en 是汇点 { int u = pre[st] = st, ma = 0, aug = inf, v; bfs(en); for(int i = 0; i <= n; i++) cur[i] = net[i]; while(dis[st] <= n) { loop: for(int &i = cur[u]; v = E[i].v, i != -1; i = E[i].next) if(E[i].cap && dis[u] == dis[v] + 1) { aug = std::min(aug, E[i].cap); pre[v] = u, u = v; if(v == en) { ma += aug; for(u = pre[u]; v != st; v = u, u = pre[u]) { E[cur[u]].cap -= aug; E[cur[u]^1].cap += aug; } aug = inf; } goto loop; } int mi = n; for(int i = net[u]; v = E[i].v, i != -1; i = E[i].next) if(E[i].cap && mi > dis[v]) { cur[u] = i; mi = dis[v]; } if(--gap[dis[u]] == 0) break; gap[dis[u]=mi+1]++; u = pre[u]; } return ma; } }; MaxFlow G; int main() { int t, n, m, st, en, temp; long long sum; scanf("%d", &t); while(t--) { scanf("%d %d", &n, &m); st = 0, en = n + m + 1; G.init(en); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { scanf("%d", &temp); if(temp == 2) G.add_edge(i, j+n, 1); } sum = 0; for(int i = 1; i <= m; i++) { scanf("%d", &temp); sum += temp; } for(int i = 1; i <= n; i++) G.add_edge(st, i, 1); for(int i = 1; i <= m; i++) G.add_edge(i+n, en, inf); if(((long long)n+G.isap(st, en)) >= sum) puts("Yes"); else puts("No"); } return 0; }
相关文章推荐
- joj 2453 candy 网络流建图的题
- JOJ 2453 Candy 网络流
- JOJ 2453 Candy
- JOJ 2453 Candy
- hdu - 4322 - Candy - 网络流
- BOJ313 Candy [网络流 dinic]
- 【总结】神奇的上下界网络流----- (总结by : becauseofyou)
- [上下界网络流] BZOJ2406: 矩阵
- 【转】 一些图论、网络流入门题总结、汇总
- 数据结构之网络流入门(Network Flow)简单小节
- 网络流(模板)
- 【二分+上下界网络流】BZOJ2406 矩阵
- poj 3680(网络流)
- UVa563_Crimewave(网络流/最大流)(小白书图论专题)
- HDU3549 Flow Problem(网络流增广路算法)
- 网络流(最大流)基础入门
- Children of the Candy Corn(BFS+DFS POJ3083)
- POJ 1637 浅谈混合图欧拉回路网络流建模
- 网络流算法模板
- bzoj 2406: 矩阵 二分答案+上下界网络流