HDU

来源:互联网 发布:网络好卡怎么办 编辑:程序博客网 时间:2024/06/07 22:09

传送门:HDU 5855

题意:

nm 
tipayi 
kkproi 
propayLtp

显然要满足最长的时间最短要二分,我们将商店向工厂连边,由于商店需要的所有工厂都要建设才能使商店获利,因此显然最后选择出来的

商店和工厂的点集是一个闭合子图,那么题目自然就是求最大权闭合子图啦,剩下的就是老套路了。

第一次自己做出来比赛题中的网络流,虽说是个签到题吧,但是还是美滋滋啊。

代码:

//ISAP int#include <iostream>#include <cstdio>#include <cstring>#include <queue>#define ll long long#define MAXN 10005#define inf 0x3f3f3f3fusing namespace std;typedef pair<int, int> P;int n;//实际建图点数(最好比图中总点数大一点)struct Edge{int v,next;int cap,flow;}edge[MAXN*100];int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN];int cnt=0;//实际存储总边数 void init(){cnt=0;memset(pre,-1,sizeof(pre)); }void add(int u,int v,int w,int rw=0)//加边 有向图三个参数,无向图四个 {edge[cnt].v=v;edge[cnt].cap=w;edge[cnt].flow=0;edge[cnt].next=pre[u];pre[u]=cnt++;edge[cnt].v=u;edge[cnt].cap=rw;edge[cnt].flow=0;edge[cnt].next=pre[v];pre[v]=cnt++;}bool bfs(int s,int t)//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长 {memset(dep,-1,sizeof(dep));memset(gap,0,sizeof(gap));gap[0]=1;dep[t]=0;queue<int>q;while(!q.empty())q.pop();q.push(t);//从汇点开始反向建层次图 while(!q.empty()){int u=q.front();q.pop();for(int i=pre[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量{dep[v]=dep[u]+1;gap[dep[v]]++;q.push(v);//if(v==s)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定 //break;}}}return dep[s]!=-1; }int isap(int s,int t){bfs(s,t);memcpy(cur,pre,sizeof(pre));int u=s;path[u]=-1;int ans=0;while(dep[s]<n)//迭代寻找增广路 {if(u==t){int f=inf;for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增广路 f=min(f,edge[i].cap-edge[i].flow);for(int i=path[u];i!=-1;i=path[edge[i^1].v]){edge[i].flow+=f;edge[i^1].flow-=f;}ans+=f;u=s;continue;}bool flag=false;int v;for(int i=cur[u];i!=-1;i=edge[i].next){v=edge[i].v;if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow){cur[u]=path[v]=i;//当前弧优化 flag=true;break;}}if(flag){u=v;continue;}int x=n;if(!(--gap[dep[u]]))return ans;//gap优化 for(int i=pre[u];i!=-1;i=edge[i].next){if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x){x=dep[edge[i].v];cur[u]=i;//常数优化 }}dep[u]=x+1;gap[dep[u]]++;if(u!=s)//当前点没有增广路则后退一个点 u=edge[path[u]^1].v; }  return ans;}struct plant{int pay, t;}p[220];int val[220];int N, M, L, source, sink;vector<int> shop[220];int build(int up){bool flag = 0;int sum = 0;for(int i = 1; i <= M; i++){flag = 0;for(int j = 0; j < shop[i].size(); j++){if(p[shop[i][j]].t > up) flag = 1;}if(flag) continue;add(source, i, val[i]);sum += val[i];for(int j = 0; j < shop[i].size(); j++){add(i, M + shop[i][j], inf);}}for(int i = 1; i <= N; i++){add(i + M, sink, p[i].pay);}return sum;}P solve(int up){source = 0, sink = N + M + 1;n = sink + 1;int l = 0, r = up + 1, mid, sum, tmp, max_flow;while(l <= r){mid = (l + r) >> 1;init();sum = build(mid);tmp = isap(source, sink);if(sum - tmp >= L)r = mid - 1, max_flow = sum - tmp;elsel = mid + 1;}return P(r + 1, max_flow);}int main(){int T, kase = 1;int k, u, v;cin >> T;while(T--){int up = 0;scanf("%d %d %d", &N, &M, &L);for(int i = 0; i <= M; i++) shop[i].clear();for(int i = 1; i <= N; i++){scanf("%d %d", &p[i].pay, &p[i].t);up = max(up, p[i].t);}for(int i = 1; i <= M; i++){scanf("%d", val + i);scanf("%d", &k);while(k--){scanf("%d", &u);shop[i].push_back(u);}}P ans = solve(up);if(ans.first > up) printf("Case #%d: impossible\n", kase++);else printf("Case #%d: %d %d\n", kase++, ans.first, ans.second);}}


原创粉丝点击