挑戰中node
問題編號ios |
問題名稱數組 |
問題模型網絡 |
轉化模型dom |
1oop |
飛行員配對方案問題優化 |
二分圖最大匹配spa |
網絡最大流 code |
2blog |
太空飛行計劃問題 |
最大權閉合圖 |
網絡最小割 |
3 |
最小路徑覆蓋問題 |
有向無環圖最小路徑覆蓋 |
網絡最大流 |
4 |
魔術球問題 |
有向無環圖最小路徑覆蓋 |
網絡最大流 |
5 |
圓桌問題 |
二分圖多重匹配 |
網絡最大流 |
6 |
最長遞增子序列問題 |
最多不相交路徑 |
網絡最大流 |
7 |
試題庫問題 |
二分圖多重匹配 |
網絡最大流 |
8 |
機器人路徑規劃問題 |
(未解決) |
最小費用最大流 |
9 |
方格取數問題 |
二分圖點權最大獨立集 |
網絡最小割 |
10 |
餐巾計劃問題 |
線性規劃網絡優化 |
最小費用最大流 |
11 |
航空路線問題 |
最長不相交路徑 |
最小費用最大流 |
12 |
軟件補丁問題 |
最小轉移代價 |
最短路徑 |
13 |
星際轉移問題 |
網絡斷定 |
網絡最大流 |
14 |
孤島營救問題 |
分層圖最短路徑 |
最短路徑 |
15 |
汽車加油行駛問題 |
分層圖最短路徑 |
最短路徑 |
16 |
數字梯形問題 |
最大權不相交路徑 |
最小費用最大流 |
17 |
運輸問題 |
網絡費用流量 |
最小費用最大流 |
18 |
分配問題 |
二分圖最佳匹配 |
最小費用最大流 |
19 |
負載平衡問題 |
最小代價供求 |
最小費用最大流 |
20 |
深海機器人問題 |
線性規劃網絡優化 |
最小費用最大流 |
21 |
最長k可重區間集問題 |
最大權不相交路徑 |
最小費用最大流 |
22 |
最長k可重線段集問題 |
最大權不相交路徑 |
最小費用最大流 |
23 |
火星探險問題 |
線性規劃網絡優化 |
最小費用最大流 |
24 |
騎士共存問題 |
二分圖最大獨立集 |
網絡最小割 |
https://www.oj.swust.edu.cn/problem/show/1736
二分圖最大匹配。超級源點連外籍飛行員,容量爲1。匹配的外籍和英國飛行員間連一條邊,容量爲1。英國飛行員與超級匯點連一條邊,容量爲1。跑最大流,輸出匹配的對。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <ctime> #include <vector> #include <queue> #include <map> #include <stack> #include <set> #include <bitset> using namespace std; typedef long long ll; typedef unsigned long long ull; #define ms(a, b) memset(a, b, sizeof(a)) #define pb push_back #define mp make_pair #define pii pair<int, int> #define IOS ios::sync_with_stdio(0);cin.tie(0); #define random(a, b) rand()*rand()%(b-a+1)+a #define pi acos(-1) const ll INF = 0x3f3f3f3f3f3f3f3fll; const int inf = 0x3f3f3f3f; const int maxn = 1000 + 10; const int maxm = 3000000 +10; const int mod = 1000000000; int maze[maxn][maxn]; int gap[maxn],dis[maxn],pre[maxn],cur[maxn]; int sap(int start,int ed,int nodenum){ memset(cur,0,sizeof(cur)); memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); int u = pre[start]=start,maxflow=0,aug=-1; gap[0]=nodenum; while(dis[start]<nodenum){ loop: for(int v =cur[u];v<nodenum;v++){ if(maze[u][v]&&dis[u]==dis[v]+1){ if(aug==-1||aug>maze[u][v]) aug = maze[u][v]; pre[v]=u; u=cur[u]=v; if(v==ed){ maxflow+=aug; for(u=pre[u];v!=start;v=u,u=pre[u]){ maze[u][v]-=aug; maze[v][u]+=aug; } aug=-1; } goto loop; } } int mindis = nodenum-1; for(int v=0;v<nodenum;v++){ if(maze[u][v]&&mindis>dis[v]){ cur[u]=v; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } int main(){ #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL int n,m; while(~scanf("%d%d",&m,&n)){ memset(maze,0,sizeof(maze)); for(int i=1;i<=m;i++) maze[0][i]=1; for(int i=m+1;i<=n;i++) maze[i][n+1]=1; int x,y; while(true){ scanf("%d%d",&x,&y); if(x==-1&&y==-1) break; maze[x][y]=1; } int ans=sap(0,n+1,n+2); cout<<ans<<endl; for(int i=1;i<=m;i++){ for(int j=m+1;j<=n;j++){ if(maze[i][j]==0&&maze[j][i]==1){ printf("%d %d\n",i,j); break; } } } } return 0; }
https://www.oj.swust.edu.cn/problem/show/1737
有一個有向圖,每個點都有一個權值(能夠爲正或負或0),選擇一個權值和最大的子圖,使得每一個點的後繼都在子圖裏面,這個子圖就叫最大權閉合子圖。
這題就是求最大權閉合子圖,轉化爲最小割來解決。把S向正費用點連邊,T向負費用點連邊,原圖的邊間連+oo
而後作最小割=min(未選收益+選花費)
答案=選收益-選花費=全選收益-(未選收益+選花費)
最大權閉合圖的點就是從起點開始廣搜,權值爲0的點不走,能走到的點就是被選中的點。
dinic最後一次bfs的dep數組正好能夠用來判斷這個條件。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <ctime> #include <vector> #include <queue> #include <map> #include <stack> #include <set> #include <bitset> using namespace std; typedef long long ll; typedef unsigned long long ull; #define ms(a, b) memset(a, b, sizeof(a)) #define pb push_back #define mp make_pair #define pii pair<int, int> #define IOS ios::sync_with_stdio(0);cin.tie(0); #define random(a, b) rand()*rand()%(b-a+1)+a #define pi acos(-1) const ll INF = 0x3f3f3f3f3f3f3f3fll; const int inf = 0x3f3f3f3f; const int maxn = 2000 + 10; const int maxm = 1000000 +10; const int mod = 1000000000; struct Edge{ int to,nxt,cap,flow; }edge[maxm]; int tol; int head[maxn]; void init(){ tol = 2; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w,int rw=0){ edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0; edge[tol].nxt=head[u];head[u]=tol++; edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0; edge[tol].nxt=head[v];head[v]=tol++; } int Q[maxn]; int dep[maxn],cur[maxn],sta[maxn]; bool bfs(int s,int t,int n){ int fron=0,tail=0; memset(dep,-1,sizeof(dep[0])*(n+1)); dep[s]=0; Q[tail++]=s; while(fron<tail){ int u =Q[fron++]; for(int i=head[u];~i;i=edge[i].nxt){ int v =edge[i].to; if(edge[i].cap>edge[i].flow&&dep[v]==-1){ dep[v]=dep[u]+1; if(v==t) return true; Q[tail++]=v; } } } return false; } int dinic(int s,int t,int n){ int maxflow=0; while(bfs(s,t,n)){ for(int i=0;i<n;i++) cur[i]=head[i]; int u=s,tail=0; while(cur[s]!=-1){ if(u==t){ int tp=inf; for(int i=tail-1;i>=0;i--){ tp=min(tp,edge[sta[i]].cap-edge[sta[i]].flow); } maxflow+=tp; for(int i=tail-1;i>=0;i--){ edge[sta[i]].flow+=tp; edge[sta[i]^1].flow-=tp; if(edge[sta[i]].cap-edge[sta[i]].flow==0) tail=i; } u=edge[sta[tail]^1].to; }else if(cur[u]!=-1&&edge[cur[u]].cap>edge[cur[u]].flow&&dep[u]+1==dep[edge[cur[u]].to]){ sta[tail++]=cur[u]; u=edge[cur[u]].to; }else{ while(u!=s&&cur[u]==-1){ u=edge[sta[--tail]^1].to; } cur[u]=edge[cur[u]].nxt; } } } return maxflow; } int main(){ #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL int n,m; init(); scanf("%d%d",&m,&n); int sum=0; for(int i=1;i<=m;i++){ int x; char c; scanf("%d",&x); sum+=x; addedge(0,i,x); while(true){ scanf("%d%c",&x,&c); addedge(i,m+x,inf); if(c=='\n'||c=='\r') break; } } for(int i=1;i<=n;i++){ int x; scanf("%d",&x); addedge(i+m,n+m+1,x); } sum-=dinic(0,n+m+1,n+m+2); for(int i=1;i<=m;i++) if(dep[i]!=-1) printf("%d ",i); puts(""); for(int i=1;i<=n;i++) if(dep[i+m]!=-1) printf("%d ",i); puts(""); printf("%d\n",sum); return 0; }