[網路流24題-11]太空飛行問題
阿新 • • 發佈:2018-12-10
太空飛行計劃問題
貌似叫最大權閉合子圖?(反正這些高階大氣上檔次的名詞我都不知道)
建模比較有趣
先想最大流 大概是源連實驗 實驗連儀器 儀器連匯 然後發現無論怎麼分配都做不到捆綁並只計算一次費用 棄療
最小費用最大流 怎麼建都是所有點都選才是最大流 更不靠譜 棄療
最小割(不要問我為什麼沒想上下界 因為我還沒學會)
我們發現按照上述最大流的建圖方法 然後實驗和儀器之間流量為inf 這樣的話就可以保證一個實驗和他需要的儀器捆綁
實驗和源點之間是貢獻 儀器和匯點之間是費用 這樣的話就構成了這個模型
貢獻可以這麼考慮 本來我們選擇的是所有的總貢獻 所以割掉一條邊其實是減去了貢獻 費用更好理解了 割掉了就是花掉了嘛
所以我們根據最大流=最小割跑一遍最大流
然後看跟源點相連的實驗和儀器就是要選的 所以這個問題就解決啦
這個題讀入真的毒瘤(大霧)
附程式碼。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<vector> #include<iostream> #define inf 20021225 #define ll long long using namespace std; queue<int> que; int dis[110],cnt=1,in[110],s,t; struct edge{int to,lt,f;}e[60000]; void add(int x,int y,int f) { e[++cnt].to=y;e[cnt].lt=in[x];e[cnt].f=f;in[x]=cnt; e[++cnt].to=x;e[cnt].lt=in[y];e[cnt].f=0;in[y]=cnt; } bool bfs(int f) { while(!que.empty()) que.pop(); memset(dis,0,sizeof(dis)); que.push(s);dis[s]=1; while(!que.empty()) { int x=que.front();que.pop();//printf("%d",x); for(int i=in[x];i;i=e[i].lt) { int y=e[i].to; //printf("%d %d\n",y,e[i].f); if(!dis[y]&&e[i].f) { dis[y]=dis[x]+1;//printf("%d\n",y); if(y==t&&f) return 1; que.push(y); } } } return 0; } int dfs(int x,int flow) { if(x==t||!flow) return flow; int cur=flow; for(int i=in[x];i;i=e[i].lt) { int y=e[i].to; if(dis[y]==dis[x]+1&&e[i].f) { int tmp=dfs(y,min(cur,e[i].f)); e[i].f-=tmp;e[i^1].f+=tmp;cur-=tmp; if(!cur) return flow; } } dis[x]=-1; return flow-cur; } bool vis[110]; int dinic() { int ans=0; while(bfs(1)) ans+=dfs(s,inf); bfs(0);return ans; } char tools[10000]; int c[110],ee[110]; vector<int> v[110]; int main() { int n,m,i,tot=0; scanf("%d%d",&m,&n); s=m+n+1;t=s+1; for(i=1;i<=m;i++) { scanf("%d",&c[i]); add(s,i,c[i]); memset(tools,0,sizeof tools); cin.getline(tools,10000); int ulen=0,tool; while (sscanf(tools+ulen,"%d",&tool)==1) { add(i,tool+m,inf);v[i].push_back(tool); //printf("%d\n",tool); if (tool==0) ulen++; else { while (tool) { tool/=10; ulen++; } } ulen++; } } for(i=1;i<=n;i++) scanf("%d",&ee[i]),add(i+m,t,ee[i]); dinic(); for(i=1;i<=m;i++) if(dis[i]) printf("%d ",i),tot+=c[i]; printf("\n"); for(i=1;i<=n;i++) if(dis[i+m]) printf("%d ",i),tot-=ee[i]; printf("\n%d\n",tot); return 0; }