博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络流23题
阅读量:5305 次
发布时间:2019-06-14

本文共 66924 字,大约阅读时间需要 223 分钟。

二分图匹配

1 #include
2 using namespace std; 3 bool vis[101]; 4 int match[101] , head[101] , cnt; 5 struct Edge{ 6 int end , upEd; 7 }Ed[10001]; 8 inline void add(int a , int b){ 9 Ed[++cnt].end = b; Ed[cnt].upEd = head[a]; head[a] = cnt;10 }11 bool dfs(int a){12 for(int i = head[a] ; i ; i = Ed[i].upEd)13 if(!vis[Ed[i].end]){14 vis[Ed[i].end] = 1;15 if(!match[Ed[i].end] || dfs(match[Ed[i].end])){16 match[Ed[i].end] = a;17 return 1;18 }19 }20 return 0;21 }22 int main(){23 int M , N , ans = 0 , a , b;24 scanf("%d%d%d%d" , &M , &N , &a , &b);25 while(a != -1){26 add(a , b - M);27 scanf("%d%d" , &a , &b);28 }29 for(int i = 1 ; i <= M ; i++){30 memset(vis , 0 , sizeof(vis));31 dfs(i);32 }33 for(int i = 1 ; i + M <= N ; i++) ans += (bool)match[i];34 if(ans == 0) cout << "No Solution!";35 else{36 cout << ans << endl;37 for(int i = 1 ; i + M <= N ; i++)38 if(match[i]) cout << match[i] << ' ' << i + M << endl;39 }40 return 0;41 }
飞行员配对方案

环形均分纸牌

1 #include
2 using namespace std; 3 inline int read(){ 4 int a = 0; 5 char c = getchar(); 6 while(!isdigit(c)) c = getchar(); 7 while(isdigit(c)) a = (a << 3) + (a << 1) + (c ^ '0') , c = getchar(); 8 return a; 9 }10 inline int abs(int a){11 return a > 0 ? a : -a;12 }13 long long S[1000001];14 int main(){15 int n = read();16 long long sum = 0;17 for(int i = 1 ; i <= n ; i++)18 sum += S[i] = read();19 sum /= n;20 for(int i = 1 ; i <= n ; i++)21 S[i] += S[i - 1] - sum;22 sort(S + 1 , S + n + 1);23 sum = 0;24 for(int i = 1 ; i <= n ; i++)25 sum += abs(S[i] - S[n + 1 >> 1]);26 printf("%lld" , sum);27 return 0;28 }
负载平衡

拆点二分图匹配/网络流,建图如下

1 #include
2 #define MAXN 1050 3 using namespace std; 4 5 inline int read(){ 6 int a = 0; 7 char c = getchar(); 8 while(!isdigit(c)) 9 c = getchar(); 10 while(isdigit(c)){ 11 a = (a << 3) + (a << 1) + (c ^ '0'); 12 c = getchar(); 13 } 14 return a; 15 } 16 17 struct Edge{ 18 int end , upEd , flow; 19 }Ed[MAXN * MAXN << 1]; 20 int flo[MAXN] , now[MAXN] , head[MAXN] , N , K , M , cntEd = 1; 21 queue < int > q; 22 bool vis[MAXN]; 23 24 inline void addEd(int a , int b , int c){ 25 Ed[++cntEd].end = b; 26 Ed[cntEd].upEd = head[a]; 27 Ed[cntEd].flow = c; 28 head[a] = cntEd; 29 } 30 31 bool bfs(){ 32 while(!q.empty()) 33 q.pop(); 34 q.push(0); 35 memset(vis , 0 , sizeof(vis)); 36 vis[0] = flo[0] = 1; 37 while(!q.empty()){ 38 int t = q.front(); 39 q.pop(); 40 for(int i = head[t] ; i ; i = Ed[i].upEd) 41 if(!vis[Ed[i].end] && Ed[i].flow){ 42 vis[Ed[i].end] = 1; 43 flo[Ed[i].end] = flo[t] + 1; 44 if(Ed[i].end == N + K + 1){ 45 memcpy(now , head , sizeof(head)); 46 return 1; 47 } 48 q.push(Ed[i].end); 49 } 50 } 51 return 0; 52 } 53 54 bool Dinic(int dir){ 55 if(dir == N + K + 1) 56 return 1; 57 for(int &i = now[dir] ; i ; i = Ed[i].upEd) 58 if(flo[Ed[i].end] == flo[dir] + 1 && Ed[i].flow) 59 if(Dinic(Ed[i].end)){ 60 Ed[i].flow--; 61 Ed[i ^ 1].flow++; 62 return 1; 63 } 64 return 0; 65 } 66 67 void output(){ 68 for(int i = 1 ; i <= K ; i++){ 69 cout << i << ':'; 70 for(int j = head[i] ; j ; j = Ed[j].upEd) 71 if(Ed[j].end && !Ed[j].flow) 72 cout << ' ' << Ed[j].end - K; 73 cout << endl; 74 } 75 } 76 77 int main() 78 { 79 K = read(); 80 N = read(); 81 for(int i = 1 ; i <= K ; i++){ 82 int a = read(); 83 M += a; 84 addEd(0 , i , a); 85 addEd(i , 0 , 0); 86 } 87 for(int i = 1 ; i <= N ; i++){ 88 addEd(K + i , K + N + 1 , 1); 89 addEd(K + N + 1 , K + i , 0); 90 for(int j = read() ; j ; j--){ 91 int a = read(); 92 addEd(a , K + i , 1); 93 addEd(K + i , a , 0); 94 } 95 } 96 while(M && bfs()) 97 while(M && Dinic(0)) 98 M--; 99 if(M)100 cout << "No Solution!";101 else102 output();103 return 0;104 }
试题库

二分图带权最大独立集=总权值-二分图最小点集覆盖=总权值-最小割=总权值-最大流

注意格子之间的边不能正反都建无穷流(这代表的是无向图,在这里WA了两发还没看出来)

1 #include
2 #define INF 0x3f3f3f3f 3 #define MAXN 10010 4 using namespace std; 5 6 inline int read(){ 7 int a = 0; 8 char c = getchar(); 9 while(!isdigit(c)) 10 c = getchar(); 11 while(isdigit(c)){ 12 a = (a << 3) + (a << 1) + (c ^ '0'); 13 c = getchar(); 14 } 15 return a; 16 } 17 18 struct Edge{ 19 int end , upEd , flow; 20 }Ed[MAXN << 2]; 21 int head[MAXN] , flo[MAXN] , now[MAXN] , M , N , ans , cntEd = 1; 22 queue < int > q; 23 bool vis[MAXN]; 24 25 inline void addEd(int a , int b , int c){ 26 Ed[++cntEd].end = b; 27 Ed[cntEd].upEd = head[a]; 28 Ed[cntEd].flow = c; 29 head[a] = cntEd; 30 } 31 32 bool bfs(){ 33 while(!q.empty()) 34 q.pop(); 35 q.push(0); 36 memset(vis , 0 , sizeof(vis)); 37 vis[0] = flo[0] = 1; 38 while(!q.empty()){ 39 int t = q.front(); 40 q.pop(); 41 for(int i = head[t] ; i ; i = Ed[i].upEd) 42 if(!vis[Ed[i].end] && Ed[i].flow){ 43 vis[Ed[i].end] = 1; 44 flo[Ed[i].end] = flo[t] + 1; 45 if(Ed[i].end == N * M + 1){ 46 memcpy(now , head , sizeof(head)); 47 return 1; 48 } 49 q.push(Ed[i].end); 50 } 51 } 52 return 0; 53 } 54 55 int Dinic(int dir , int minN){ 56 if(dir == N * M + 1) 57 return minN; 58 for(int &i = now[dir] ; i ; i = Ed[i].upEd) 59 if(Ed[i].flow && flo[Ed[i].end] == flo[dir] + 1){ 60 int t = Dinic(Ed[i].end , min(minN , Ed[i].flow)); 61 if(t){ 62 Ed[i].flow -= t; 63 Ed[i ^ 1].flow += t; 64 return t; 65 } 66 } 67 return 0; 68 } 69 70 int main(){ 71 M = read(); 72 N = read(); 73 for(int i = 0 ; i < M ; i++) 74 for(int j = 1 ; j <= N ; j++){ 75 int a = read(); 76 ans += a; 77 if(i + j & 1){ 78 addEd(0 , i * N + j , a); 79 addEd(i * N + j , 0 , 0); 80 if(i < M - 1){ 81 addEd(i * N + j , (i + 1) * N + j , INF); 82 addEd((i + 1) * N + j , i * N + j , 0); 83 } 84 if(j < N){ 85 addEd(i * N + j , i * N + j + 1 , INF); 86 addEd(i * N + j + 1 , i * N + j , 0); 87 } 88 if(i){ 89 addEd(i * N + j , (i - 1) * N + j , INF); 90 addEd((i - 1) * N + j , i * N + j , 0); 91 } 92 if(j - 1){ 93 addEd(i * N + j , i * N + j - 1 , INF); 94 addEd(i * N + j - 1 , i * N + j , 0); 95 } 96 } 97 else{ 98 addEd(i * N + j , N * M + 1 , a); 99 addEd(N * M + 1 , i * N + j , 0);100 }101 102 }103 int K;104 while(bfs())105 while(K = Dinic(0 , INF))106 ans -= K;107 cout << ans;108 return 0;109 }
方格取数

注意到这是一个有上下界网络流

拆点,每一天对应两个点:早上和晚上

连边如下:

$S$向每一天晚上连$need_i$流量、$0$费用边表示当天多出了$need_i$块脏餐巾

每一天早上向$T$连$need_i$流量、$0$费用边表示当天需要$need_i$块干净餐巾

$S$向第一天早上连$(INF,p)$边表示购买

$i$天早上向$i+1$天早上连$(INF,0)$表示干净的餐巾可以存下来

然后晚上向对应的早上连清洗的时间和费用就行了

一定不能把边建成$S->$早上$->$晚上$->T$,因为这种连边方式没有限制下界

1 #include
2 #define INF 0x7fffffff 3 #define int long long 4 //This code is written by Itst 5 using namespace std; 6 7 inline int read(){ 8 int a = 0; 9 char c = getchar(); 10 bool f = 0; 11 while(!isdigit(c) && c != EOF){ 12 if(c == '-') 13 f = 1; 14 c = getchar(); 15 } 16 if(c == EOF) 17 exit(0); 18 while(isdigit(c)){ 19 a = (a << 3) + (a << 1) + (c ^ '0'); 20 c = getchar(); 21 } 22 return f ? -a : a; 23 } 24 25 const int MAXN = 4010 , MAXM = 30010; 26 struct Edge{ 27 int end , upEd , f , c; 28 }Ed[MAXM]; 29 int head[MAXN] , dis[MAXN] , pre[MAXN] , flo[MAXN] , need[MAXN]; 30 int N , p , m , f , n , s , S , T , cntEd = 1; 31 bool vis[MAXN]; 32 queue < int > q; 33 34 inline void addEd(int a , int b , int c , int d = 0){ 35 Ed[++cntEd].end = b; 36 Ed[cntEd].upEd = head[a]; 37 Ed[cntEd].f = c; 38 Ed[cntEd].c = d; 39 head[a] = cntEd; 40 } 41 42 inline bool SPFA(){ 43 memset(dis , 0x3f , sizeof(dis)); 44 dis[S] = 0; 45 while(!q.empty()) 46 q.pop(); 47 q.push(S); 48 flo[S] = INF; 49 while(!q.empty()){ 50 int t = q.front(); 51 q.pop(); 52 vis[t] = 0; 53 for(int i = head[t] ; i ; i = Ed[i].upEd) 54 if(Ed[i].f && dis[Ed[i].end] > dis[t] + Ed[i].c){ 55 dis[Ed[i].end] = dis[t] + Ed[i].c; 56 flo[Ed[i].end] = min(Ed[i].f , flo[t]); 57 pre[Ed[i].end] = i; 58 if(!vis[Ed[i].end]){ 59 vis[Ed[i].end] = 1; 60 q.push(Ed[i].end); 61 } 62 } 63 } 64 return dis[T] != dis[T + 1]; 65 } 66 67 void input(){ 68 N = read(); 69 for(int i = 1 ; i <= N ; ++i) 70 need[i] = read(); 71 p = read(); 72 m = read(); 73 f = read(); 74 n = read(); 75 s = read(); 76 } 77 78 void init(){ 79 S = 0; 80 T = 2 * N + 1; 81 addEd(S , 1 , INF , p); 82 addEd(1 , S , 0 , -p); 83 for(int i = 1 ; i <= N ; ++i){ 84 addEd(i , T , need[i]); 85 addEd(T , i , 0); 86 addEd(S , i + N , need[i]); 87 addEd(i + N , S , 0); 88 } 89 for(int i = 1 ; i < N ; ++i){ 90 addEd(i , i + 1 , INF); 91 addEd(i + 1 , i , 0); 92 } 93 for(int i = 1 ; i + m <= N ; ++i){ 94 addEd(i + N , i + m , INF , f); 95 addEd(i + m , i + N , 0 , -f); 96 } 97 for(int i = 1 ; i + n <= N ; ++i){ 98 addEd(i + N , i + n , INF , s); 99 addEd(i + n , i + N , 0 , -s);100 }101 }102 103 void work(){104 int ans = 0;105 while(SPFA()){106 int cur = T , sum = 0;107 while(cur != S){108 Ed[pre[cur]].f -= flo[T];109 Ed[pre[cur] ^ 1].f += flo[T];110 sum += Ed[pre[cur]].c;111 cur = Ed[pre[cur] ^ 1].end;112 }113 ans += sum * flo[T];114 }115 cout << ans;116 }117 118 signed main(){119 #ifndef ONLINE_JUDGE120 freopen("in" , "r" , stdin);121 //freopen("out" , "w" , stdout);122 #endif123 input();124 init();125 work();126 return 0;127 }
餐巾计划

最大权闭合子图

输出方案时满足能从$S$到达某一个点就表示这一个点被选中了

1 #include
2 #define INF 0x7fffffff 3 //This code is written by Itst 4 using namespace std; 5 6 const int MAXN = 110 , MAXM = 25010; 7 struct Edge{ 8 int end , upEd , f , c; 9 }Ed[MAXM]; 10 int head[MAXN] , cur[MAXN] , dep[MAXN]; 11 int N , M , S , T , cntEd = 1 , ans; 12 bool vis[MAXN]; 13 queue < int > q; 14 15 inline void addEd(int a , int b , int c , int d = 0){ 16 Ed[++cntEd].end = b; 17 Ed[cntEd].upEd = head[a]; 18 Ed[cntEd].f = c; 19 Ed[cntEd].c = d; 20 head[a] = cntEd; 21 } 22 23 inline bool bfs(){ 24 while(!q.empty()) 25 q.pop(); 26 q.push(S); 27 memset(dep , 0 , sizeof(dep)); 28 dep[S] = 1; 29 while(!q.empty()){ 30 int t = q.front(); 31 q.pop(); 32 for(int i = head[t] ; i ; i = Ed[i].upEd) 33 if(Ed[i].f && !dep[Ed[i].end]){ 34 dep[Ed[i].end] = dep[t] + 1; 35 if(Ed[i].end == T){ 36 memcpy(cur , head , sizeof(head)); 37 return 1; 38 } 39 q.push(Ed[i].end); 40 } 41 } 42 return 0; 43 } 44 45 inline int dfs(int x , int mF){ 46 if(x == T) 47 return mF; 48 int sum = 0; 49 for(int &i = cur[x] ; i ; i = Ed[i].upEd) 50 if(Ed[i].f && dep[Ed[i].end] == dep[x] + 1){ 51 int t = dfs(Ed[i].end , min(mF - sum , Ed[i].f)); 52 if(t){ 53 Ed[i].f -= t; 54 Ed[i ^ 1].f += t; 55 sum += t; 56 if(sum == mF) 57 break; 58 } 59 } 60 return sum; 61 } 62 63 void input(){ 64 cin >> N >> M; 65 S = 0; 66 T = N + M + 1; 67 string s; 68 stringstream ss; 69 getline(cin , s); 70 for(int i = 1 ; i <= N ; ++i){ 71 ss.clear(); 72 getline(cin , s); 73 ss.str(s); 74 int K; 75 ss >> K; 76 ans += K; 77 addEd(S , i , K); 78 addEd(i , S , 0); 79 while(ss >> K){ 80 addEd(i , N + K , INF); 81 addEd(N + K , i , 0); 82 } 83 } 84 for(int i = 1 ; i <= M ; ++i){ 85 int a; 86 cin >> a; 87 addEd(i + N , T , a); 88 addEd(T , i + N , 0); 89 } 90 } 91 92 void work(){ 93 while(bfs()) 94 ans -= dfs(S , INF); 95 for(int i = head[S] ; i ; i = Ed[i].upEd) 96 if(dep[Ed[i].end]) 97 cout << Ed[i].end << ' '; 98 cout << endl; 99 for(int i = head[T] ; i ; i = Ed[i].upEd)100 if(dep[Ed[i].end])101 cout << Ed[i].end - N << ' ';102 cout << endl << ans;103 }104 105 int main(){106 #ifndef ONLINE_JUDGE107 freopen("in" , "r" , stdin);108 //freopen("out" , "w" , stdout);109 #endif110 input();111 work();112 return 0;113 }
太空飞行计划

状压最短路

1 #include
2 //This code is written by Itst 3 using namespace std; 4 5 int dp[1 << 20] , T[110] , B[110][2] , F[110][2] , N , M; 6 queue < int > q; 7 bool vis[1 << 20]; 8 9 void input(){10 ios::sync_with_stdio(0);11 cin.tie(0);12 cin >> N >> M;13 string s;14 for(int i = 1 ; i <= M ; ++i){15 cin >> T[i] >> s;16 for(int j = 0 ; j < N ; ++j)17 if(s[j] == '+')18 B[i][0] |= 1 << j;19 else20 if(s[j] == '-')21 B[i][1] |= 1 << j;22 cin >> s;23 for(int j = 0 ; j < N ; ++j)24 if(s[j] == '-')25 F[i][0] |= 1 << j;26 else27 if(s[j] == '+')28 F[i][1] |= 1 << j;29 }30 }31 32 void work(){33 memset(dp , 0x7f , sizeof(dp));34 dp[(1 << N) - 1] = 0;35 q.push((1 << N) - 1);36 while(!q.empty()){37 int t = q.front();38 q.pop();39 vis[t] = 0;40 for(int j = 1 ; j <= M ; ++j)41 if((t & B[j][0]) == B[j][0] && !(t & B[j][1])){42 int k = (t ^ (t & F[j][0])) | F[j][1];43 if(dp[k] > dp[t] + T[j]){44 dp[k] = dp[t] + T[j];45 if(!vis[k]){46 vis[k] = 1;47 q.push(k);48 }49 }50 }51 }52 }53 54 void output(){55 cout << (dp[0] == 0x7f7f7f7f ? 0 : dp[0]);56 }57 58 int main(){59 #ifndef ONLINE_JUDGE60 freopen("in" , "r" , stdin);61 //freopen("out" , "w" , stdout);62 #endif63 input();64 work();65 output();66 return 0;67 }
软件补丁

二分图最大/小权匹配裸题

1 #include
2 #define INF 0x7fffffff 3 //This code is written by Itst 4 using namespace std; 5 6 inline int read(){ 7 int a = 0; 8 char c = getchar(); 9 bool f = 0; 10 while(!isdigit(c) && c != EOF){ 11 if(c == '-') 12 f = 1; 13 c = getchar(); 14 } 15 if(c == EOF) 16 exit(0); 17 while(isdigit(c)){ 18 a = (a << 3) + (a << 1) + (c ^ '0'); 19 c = getchar(); 20 } 21 return f ? -a : a; 22 } 23 24 const int MAXN = 210 , MAXM = 21010; 25 struct Edge{ 26 int end , upEd , f , c; 27 }Ed[MAXM]; 28 int head[MAXN] , c[MAXN][MAXN] , dis[MAXN] , pre[MAXN]; 29 int N , S , T , cntEd = 1; 30 bool vis[MAXN]; 31 queue < int > q; 32 33 inline void addEd(int a , int b , int c , int d = 0){ 34 Ed[++cntEd].end = b; 35 Ed[cntEd].upEd = head[a]; 36 Ed[cntEd].f = c; 37 Ed[cntEd].c = d; 38 head[a] = cntEd; 39 } 40 41 inline bool SPFA(){ 42 memset(dis , 0x3f , sizeof(dis)); 43 dis[S] = 0; 44 while(!q.empty()) 45 q.pop(); 46 q.push(S); 47 while(!q.empty()){ 48 int t = q.front(); 49 q.pop(); 50 vis[t] = 0; 51 for(int i = head[t] ; i ; i = Ed[i].upEd) 52 if(Ed[i].f && dis[Ed[i].end] > dis[t] + Ed[i].c){ 53 dis[Ed[i].end] = dis[t] + Ed[i].c; 54 pre[Ed[i].end] = i; 55 if(!vis[Ed[i].end]){ 56 vis[Ed[i].end] = 1; 57 q.push(Ed[i].end); 58 } 59 } 60 } 61 return dis[T] != 0x3f3f3f3f; 62 } 63 64 void input(){ 65 N = read(); 66 T = N * 2 + 1; 67 for(int i = 1 ; i <= N ; ++i) 68 for(int j = 1 ; j <= N ; ++j) 69 c[i][j] = read(); 70 } 71 72 void init(int x){ 73 cntEd = 1; 74 memset(head , 0 , sizeof(head)); 75 for(int i = 1 ; i <= N ; ++i) 76 for(int j = 1 ; j <= N ; ++j){ 77 addEd(i , j + N , 1 , c[i][j] * x); 78 addEd(j + N , i , 0 , c[i][j] * -x); 79 } 80 for(int i = 1 ; i <= N ; ++i){ 81 addEd(S , i , 1); 82 addEd(i , S , 0); 83 addEd(i + N , T , 1); 84 addEd(T , i + N , 0); 85 } 86 } 87 88 void work(){ 89 init(1); 90 int ans = 0; 91 while(SPFA()){ 92 int cur = T , sum = 0; 93 while(cur != S){ 94 sum += Ed[pre[cur]].c; 95 --Ed[pre[cur]].f; 96 ++Ed[pre[cur] ^ 1].f; 97 cur = Ed[pre[cur] ^ 1].end; 98 } 99 ans += sum;100 }101 cout << ans << endl;102 init(-1);103 ans = 0;104 while(SPFA()){105 int cur = T , sum = 0;106 while(cur != S){107 sum += Ed[pre[cur]].c;108 --Ed[pre[cur]].f;109 ++Ed[pre[cur] ^ 1].f;110 cur = Ed[pre[cur] ^ 1].end;111 }112 ans += sum;113 }114 cout << -ans;115 }116 117 int main(){118 #ifndef ONLINE_JUDGE119 freopen("in" , "r" , stdin);120 //freopen("out" , "w" , stdout);121 #endif122 input();123 work();124 return 0;125 }
分配问题

同试题库问题

1 #include
2 #define INF 0x7fffffff 3 //This code is written by Itst 4 using namespace std; 5 6 inline int read(){ 7 int a = 0; 8 char c = getchar(); 9 bool f = 0; 10 while(!isdigit(c) && c != EOF){ 11 if(c == '-') 12 f = 1; 13 c = getchar(); 14 } 15 if(c == EOF) 16 exit(0); 17 while(isdigit(c)){ 18 a = (a << 3) + (a << 1) + (c ^ '0'); 19 c = getchar(); 20 } 21 return f ? -a : a; 22 } 23 24 const int MAXN = 510 , MAXM = 100010; 25 struct Edge{ 26 int end , upEd , f , c; 27 }Ed[MAXM]; 28 int head[MAXN] , cur[MAXN] , dep[MAXN]; 29 int N , M , S , T , cntEd = 1 , sum; 30 bool vis[MAXN]; 31 queue < int > q; 32 33 inline void addEd(int a , int b , int c , int d = 0){ 34 Ed[++cntEd].end = b; 35 Ed[cntEd].upEd = head[a]; 36 Ed[cntEd].f = c; 37 Ed[cntEd].c = d; 38 head[a] = cntEd; 39 } 40 41 inline bool bfs(){ 42 while(!q.empty()) 43 q.pop(); 44 q.push(S); 45 memset(dep , 0 , sizeof(dep)); 46 dep[S] = 1; 47 while(!q.empty()){ 48 int t = q.front(); 49 q.pop(); 50 for(int i = head[t] ; i ; i = Ed[i].upEd) 51 if(Ed[i].f && !dep[Ed[i].end]){ 52 dep[Ed[i].end] = dep[t] + 1; 53 if(Ed[i].end == T){ 54 memcpy(cur , head , sizeof(head)); 55 return 1; 56 } 57 q.push(Ed[i].end); 58 } 59 } 60 return 0; 61 } 62 63 inline int dfs(int x , int mF){ 64 if(x == T) 65 return mF; 66 int sum = 0; 67 for(int &i = cur[x] ; i ; i = Ed[i].upEd) 68 if(Ed[i].f && dep[Ed[i].end] == dep[x] + 1){ 69 int t = dfs(Ed[i].end , min(mF - sum , Ed[i].f)); 70 if(t){ 71 Ed[i].f -= t; 72 Ed[i ^ 1].f += t; 73 sum += t; 74 if(sum == mF) 75 break; 76 } 77 } 78 return sum; 79 } 80 81 void input(){ 82 M = read(); 83 N = read(); 84 T = N + M + 1; 85 for(int i = 1 ; i <= M ; ++i){ 86 int a = read(); 87 addEd(S , i , a); 88 addEd(i , S , 0); 89 sum += a; 90 } 91 for(int i = 1 ; i <= N ; ++i){ 92 addEd(i + M , T , read()); 93 addEd(T , i + M , 0); 94 } 95 for(int i = 1 ; i <= M ; ++i) 96 for(int j = 1 ; j <= N ; ++j){ 97 addEd(i , j + M , 1); 98 addEd(j + M , i , 0); 99 }100 }101 102 void work(){103 while(bfs())104 sum -= dfs(S , INF);105 if(sum)106 puts("0");107 else{108 puts("1");109 for(int i = 1 ; i <= M ; ++i){110 for(int j = head[i] ; j ; j = Ed[j].upEd)111 if(Ed[j].end && !Ed[j].f)112 cout << Ed[j].end - M << ' ';113 putchar('\n');114 }115 }116 }117 118 int main(){119 #ifndef ONLINE_JUDGE120 freopen("in" , "r" , stdin);121 //freopen("out" , "w" , stdout);122 #endif123 input();124 work();125 return 0;126 }
圆桌问题

每一条边对应一个流量为$1$、费用为其价值的边和一条流量为$INF$、费用为$0$的边,然后最大费用最大流

1 #include
2 #define INF 0x7fffffff 3 #define id(i , j) ((i) * (M + 1) + (j) + 1) 4 //This code is written by Itst 5 using namespace std; 6 7 inline int read(){ 8 int a = 0; 9 char c = getchar(); 10 bool f = 0; 11 while(!isdigit(c) && c != EOF){ 12 if(c == '-') 13 f = 1; 14 c = getchar(); 15 } 16 if(c == EOF) 17 exit(0); 18 while(isdigit(c)){ 19 a = (a << 3) + (a << 1) + (c ^ '0'); 20 c = getchar(); 21 } 22 return f ? -a : a; 23 } 24 25 const int MAXN = 1010 , MAXM = 20010; 26 struct Edge{ 27 int end , upEd , f , c; 28 }Ed[MAXM]; 29 int head[MAXN] , dis[MAXN] , pre[MAXN] , flo[MAXN]; 30 int N , M , a , b , S , T , cntEd = 1; 31 bool vis[MAXN]; 32 queue < int > q; 33 34 inline void addEd(int a , int b , int c , int d = 0){ 35 Ed[++cntEd].end = b; 36 Ed[cntEd].upEd = head[a]; 37 Ed[cntEd].f = c; 38 Ed[cntEd].c = d; 39 head[a] = cntEd; 40 } 41 42 inline bool SPFA(){ 43 memset(dis , -0x3f , sizeof(dis)); 44 dis[S] = 0; 45 while(!q.empty()) 46 q.pop(); 47 q.push(S); 48 flo[S] = INF; 49 while(!q.empty()){ 50 int t = q.front(); 51 q.pop(); 52 vis[t] = 0; 53 for(int i = head[t] ; i ; i = Ed[i].upEd) 54 if(Ed[i].f && dis[Ed[i].end] < dis[t] + Ed[i].c){ 55 dis[Ed[i].end] = dis[t] + Ed[i].c; 56 flo[Ed[i].end] = min(Ed[i].f , flo[t]); 57 pre[Ed[i].end] = i; 58 if(!vis[Ed[i].end]){ 59 vis[Ed[i].end] = 1; 60 q.push(Ed[i].end); 61 } 62 } 63 } 64 return dis[T] != dis[T + 1]; 65 } 66 67 int EK(){ 68 int ans = 0; 69 while(SPFA()){ 70 int cur = T , sum = 0; 71 while(cur != S){ 72 sum += Ed[pre[cur]].c; 73 Ed[pre[cur]].f -= flo[T]; 74 Ed[pre[cur] ^ 1].f += flo[T]; 75 cur = Ed[pre[cur] ^ 1].end; 76 } 77 ans += sum * flo[T]; 78 } 79 return ans; 80 } 81 82 void input(){ 83 a = read(); 84 b = read(); 85 N = read(); 86 M = read(); 87 T = id(N , M) + 1; 88 for(int i = 0 ; i <= N ; ++i) 89 for(int j = 0 ; j < M ; ++j){ 90 int k = read(); 91 addEd(id(i , j) , id(i , j + 1) , 1 , k); 92 addEd(id(i , j + 1) , id(i , j) , 0 , -k); 93 addEd(id(i , j) , id(i , j + 1) , INF); 94 addEd(id(i , j + 1) , id(i , j) , 0); 95 } 96 for(int j = 0 ; j <= M ; ++j) 97 for(int i = 0 ; i < N ; ++i){ 98 int k = read(); 99 addEd(id(i , j) , id(i + 1 , j) , 1 , k);100 addEd(id(i + 1 , j) , id(i , j) , 0 , -k);101 addEd(id(i , j) , id(i + 1 , j) , INF);102 addEd(id(i + 1 , j) , id(i , j) , 0);103 }104 for(int i = 1 ; i <= a ; ++i){105 int k = read() , p = read() , q = read();106 addEd(S , id(p , q) , k);107 addEd(id(p , q) , S , 0);108 }109 for(int i = 1 ; i <= b ; ++i){110 int k = read() , p = read() , q = read();111 addEd(id(p , q) , T , k);112 addEd(T , id(p , q) , 0);113 }114 }115 116 void work(){117 cout << EK();118 }119 120 int main(){121 #ifndef ONLINE_JUDGE122 freopen("in" , "r" , stdin);123 //freopen("out" , "w" , stdout);124 #endif125 input();126 work();127 return 0;128 }
深海机器人

给大家分享几个自己的脑残错误:

①第$N$个元素不一定在最长不下降子序列内

②题意杀……第二问中所有数字都只能取一次,第三问中同样的序列不能重复计算

但是相对来说还是很套路的

1 #include
2 #define INF 0x3f3f3f3f 3 //This code is written by Itst 4 using namespace std; 5 6 inline int read(){ 7 int a = 0; 8 char c = getchar(); 9 bool f = 0; 10 while(!isdigit(c) && c != EOF){ 11 if(c == '-') 12 f = 1; 13 c = getchar(); 14 } 15 if(c == EOF) 16 exit(0); 17 while(isdigit(c)){ 18 a = (a << 3) + (a << 1) + (c ^ '0'); 19 c = getchar(); 20 } 21 return f ? -a : a; 22 } 23 24 const int MAXN = 5010 , MAXM = 50010; 25 struct Edge{ 26 int end , upEd , f , c; 27 }Ed[MAXM]; 28 int head[MAXN] , cur[MAXN] , dep[MAXN] , dp[MAXN] , num[MAXN]; 29 int N , S , T , cntEd = 1; 30 bool vis[MAXN]; 31 queue < int > q; 32 33 inline void addEd(int a , int b , int c , int d = 0){ 34 Ed[++cntEd].end = b; 35 Ed[cntEd].upEd = head[a]; 36 Ed[cntEd].f = c; 37 Ed[cntEd].c = d; 38 head[a] = cntEd; 39 } 40 41 inline bool bfs(){ 42 while(!q.empty()) 43 q.pop(); 44 q.push(S); 45 memset(dep , 0 , sizeof(dep)); 46 dep[S] = 1; 47 while(!q.empty()){ 48 int t = q.front(); 49 q.pop(); 50 for(int i = head[t] ; i ; i = Ed[i].upEd) 51 if(Ed[i].f && !dep[Ed[i].end]){ 52 dep[Ed[i].end] = dep[t] + 1; 53 if(Ed[i].end == T){ 54 memcpy(cur , head , sizeof(head)); 55 return 1; 56 } 57 q.push(Ed[i].end); 58 } 59 } 60 return 0; 61 } 62 63 inline int dfs(int x , int mF){ 64 if(x == T) 65 return mF; 66 int sum = 0; 67 for(int &i = cur[x] ; i ; i = Ed[i].upEd) 68 if(Ed[i].f && dep[Ed[i].end] == dep[x] + 1){ 69 int t = dfs(Ed[i].end , min(mF - sum , Ed[i].f)); 70 if(t){ 71 Ed[i].f -= t; 72 Ed[i ^ 1].f += t; 73 sum += t; 74 if(sum == mF) 75 break; 76 } 77 } 78 return sum; 79 } 80 81 int Dinic(){ 82 int ans = 0; 83 while(bfs()) 84 ans += dfs(S , INF); 85 return ans; 86 } 87 88 void input(){ 89 N = read(); 90 for(int i = 1 ; i <= N ; ++i) 91 num[i] = read(); 92 } 93 94 void work(){ 95 int maxN = 0 , ans = 0; 96 for(int i = 1 ; i <= N ; ++i){ 97 for(int j = i - 1 ; j >= 0 ; --j) 98 if(num[j] <= num[i]) 99 dp[i] = max(dp[i] , dp[j] + 1);100 maxN = max(maxN , dp[i]);101 }102 dp[N + 1] = maxN + 1;103 cout << maxN << endl;104 T = N * 2 + 1;105 for(int i = 1 ; i <= N ; ++i)106 if(dp[i] == 1){107 addEd(0 , i , 1);108 addEd(i , 0 , 0);109 }110 for(int i = 1 ; i <= N ; ++i){111 addEd(i , i + N , 1);112 addEd(i + N , i , 0);113 }114 for(int i = 1 ; i <= N ; ++i)115 for(int j = i + 1 ; j <= N ; ++j)116 if(dp[j] == dp[i] + 1 && num[j] >= num[i]){117 addEd(j , i + N , 0);118 addEd(i + N , j , 1);119 }120 for(int i = 1 ; i <= N ; ++i)121 if(dp[i] == maxN){122 addEd(i + N , T , 1);123 addEd(T , i + N , 0);124 }125 ans = Dinic();126 cout << ans << endl;127 if(maxN == 1)128 cout << ans;129 else{130 addEd(0 , 1 , INF);131 addEd(1 , 0 , 0);132 if(dp[N] == maxN){133 addEd(N * 2 , T , INF);134 addEd(T , N * 2 , 0);135 }136 addEd(1 , N + 1 , INF);137 addEd(N + 1 , 1 , 0);138 addEd(N , N * 2 , INF);139 addEd(N * 2 , N , 0);140 cout << ans + Dinic() << endl;141 }142 }143 144 int main(){145 #ifndef ONLINE_JUDGE146 freopen("in" , "r" , stdin);147 //freopen("out" , "w" , stdout);148 #endif149 input();150 work();151 return 0;152 }
最长不下降子序列

费用流,没什么好说的

1 #include
2 #define INF 0x7fffffff 3 using namespace std; 4 5 inline int read(){ 6 int a = 0; 7 char c = getchar(); 8 while(!isdigit(c)) 9 c = getchar(); 10 while(isdigit(c)){ 11 a = a * 10 + c - 48; 12 c = getchar(); 13 } 14 return a; 15 } 16 17 const int MAXN = 210; 18 struct Edge{ 19 int end , upEd , f , c; 20 }Ed[MAXN * MAXN * 5]; 21 int head[MAXN] , dis[MAXN] , pre[MAXN] , flo[MAXN] , b[MAXN] , c[MAXN] , cost[MAXN][MAXN]; 22 int cntEd = 1 , S , T , N , M , ans; 23 bool vis[MAXN]; 24 queue < int > q; 25 26 inline void addEd(int a , int b , int c , int d = 0){ 27 Ed[++cntEd].end = b; 28 Ed[cntEd].upEd = head[a]; 29 Ed[cntEd].f = c; 30 Ed[cntEd].c = d; 31 head[a] = cntEd; 32 } 33 34 bool SPFA(bool f){ 35 memset(dis , f ? -0x3f : 0x3f , sizeof(dis)); 36 dis[S] = 0; 37 q.push(S); 38 flo[S] = INF; 39 while(!q.empty()){ 40 int t = q.front(); 41 q.pop(); 42 vis[t] = 0; 43 for(int i = head[t] ; i ; i = Ed[i].upEd) 44 if(Ed[i].f && (f ? dis[Ed[i].end] < dis[t] + Ed[i].c : dis[Ed[i].end] > dis[t] + Ed[i].c)){ 45 dis[Ed[i].end] = dis[t] + Ed[i].c; 46 pre[Ed[i].end] = i; 47 flo[Ed[i].end] = min(flo[t] , Ed[i].f); 48 if(!vis[Ed[i].end]){ 49 vis[Ed[i].end] = 1; 50 q.push(Ed[i].end); 51 } 52 } 53 } 54 return dis[T] != dis[T + 1]; 55 } 56 57 signed main(){ 58 N = read(); 59 M = read(); 60 T = N + M + 1; 61 for(int i = 1 ; i <= N ; ++i) 62 b[i] = read(); 63 for(int j = 1 ; j <= M ; ++j) 64 c[j] = read(); 65 for(int i = 1 ; i <= N ; ++i) 66 for(int j = 1 ; j <= M ; ++j) 67 cost[i][j] = read(); 68 for(int i = 1 ; i <= N ; ++i){ 69 addEd(S , i , b[i]); 70 addEd(i , S , 0); 71 } 72 for(int i = 1 ; i <= M ; ++i){ 73 addEd(i + N , T , c[i]); 74 addEd(T , i + N , 0); 75 } 76 for(int i = 1 ; i <= N ; ++i) 77 for(int j = 1 ; j <= M ; ++j){ 78 addEd(i , j + N , INF , cost[i][j]); 79 addEd(j + N , i , 0 , -cost[i][j]); 80 } 81 ans = 0; 82 while(SPFA(0)){ 83 int cur = T , sum = 0; 84 while(cur != S){ 85 sum += Ed[pre[cur]].c; 86 Ed[pre[cur]].f -= flo[T]; 87 Ed[pre[cur] ^ 1].f += flo[T]; 88 cur = Ed[pre[cur] ^ 1].end; 89 } 90 ans += sum * flo[T]; 91 } 92 cout << ans << endl; 93 memset(head , 0 , sizeof(head)); 94 cntEd = 1; 95 for(int i = 1 ; i <= N ; ++i){ 96 addEd(S , i , b[i]); 97 addEd(i , S , 0); 98 } 99 for(int i = 1 ; i <= M ; ++i){100 addEd(i + N , T , c[i]);101 addEd(T , i + N , 0);102 }103 for(int i = 1 ; i <= N ; ++i)104 for(int j = 1 ; j <= M ; ++j){105 addEd(i , j + N , INF , cost[i][j]);106 addEd(j + N , i , 0 , -cost[i][j]);107 }108 ans = 0;109 while(SPFA(1)){110 int cur = T , sum = 0;111 while(cur != S){112 sum += Ed[pre[cur]].c;113 Ed[pre[cur]].f -= flo[T];114 Ed[pre[cur] ^ 1].f += flo[T];115 cur = Ed[pre[cur] ^ 1].end;116 }117 ans += sum * flo[T];118 }119 cout << ans << endl;120 return 0;121 }
运输问题

分层图最短路

注意到终点时可以空油(在这里WA#4调了好久QAQ)

1 #include
2 using namespace std; 3 4 inline int read(){ 5 int a = 0; 6 char c = getchar(); 7 while(!isdigit(c)) 8 c = getchar(); 9 while(isdigit(c)){10 a = a * 10 + c - 48;11 c = getchar();12 }13 return a;14 }15 16 const int dir[4][2] = {
0,1,1,0,-1,0,0,-1};17 int dis[110][110][11] , Map[110][110] , cost[4];18 int N , K , A , C; 19 struct que{20 int d , a , b , c;21 bool operator <(const que l)const{22 return d > l.d;23 }24 }now;25 priority_queue < que > q;26 27 #define AD now.a + dir[i][0]28 #define BD now.b + dir[i][1]29 int Dijk(){30 memset(dis , 0x7f , sizeof(dis));31 dis[1][1][0] = 0;32 q.push((que){
0 , 1 , 1 , 0});33 while(!q.empty()){34 now = q.top();35 q.pop();36 if(now.d > dis[now.a][now.b][now.c])37 continue;38 if(now.a == N && now.b == N)39 return now.d;40 for(int i = 0 ; i < 4 ; ++i)41 if(AD > 0 && AD <= N)42 if(BD > 0 && BD <= N){43 int cnt = now.d + cost[i] , c = now.c + 1;44 if(c > K){45 cnt += C + A;46 c = 1;47 }48 if(Map[AD][BD]){49 cnt += A;50 c = 0;51 }52 if(dis[AD][BD][c] > cnt){53 dis[AD][BD][c] = cnt;54 q.push((que){dis[AD][BD][c] , AD , BD , c});55 }56 }57 }58 }59 60 signed main(){61 N = read();62 K = read();63 A = read();64 cost[2] = cost[3] = read();65 C = read();66 for(int i = 1 ; i <= N ; ++i)67 for(int j = 1 ; j <= N ; ++j)68 Map[i][j] = read();69 cout << Dijk();70 return 0;71 }
汽车加油行驶

同餐巾计划问题,是一个有上下界网络流

每个图上的点拆成$AB$两个点,$S->B$,$A->T$,然后图上的有向边$x->y$在网络流中对应$B_x->A_y$

最大流之后每一条流满的$B_x->A_y$边表示边$x->y$被选中

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #define INF 0x3f3f3f3f 17 //This code is written by Itst 18 using namespace std; 19 20 inline int read(){ 21 int a = 0; 22 char c = getchar(); 23 bool f = 0; 24 while(!isdigit(c) && c != EOF){ 25 if(c == '-') 26 f = 1; 27 c = getchar(); 28 } 29 if(c == EOF) 30 exit(0); 31 while(isdigit(c)){ 32 a = (a << 3) + (a << 1) + (c ^ '0'); 33 c = getchar(); 34 } 35 return f ? -a : a; 36 } 37 38 const int MAXN = 1010 , MAXM = 20010; 39 struct Edge{ 40 int end , upEd , f , c; 41 }Ed[MAXM]; 42 int head[MAXN] , cur[MAXN] , dep[MAXN] , dis[MAXN] , pre[MAXN] , flo[MAXN]; 43 int N , M , S , T , cntEd = 1; 44 bool vis[MAXN]; 45 queue < int > q; 46 47 inline void addEd(int a , int b , int c , int d = 0){ 48 Ed[++cntEd].end = b; 49 Ed[cntEd].upEd = head[a]; 50 Ed[cntEd].f = c; 51 Ed[cntEd].c = d; 52 head[a] = cntEd; 53 } 54 55 inline bool bfs(){ 56 while(!q.empty()) 57 q.pop(); 58 q.push(S); 59 memset(dep , 0 , sizeof(dep)); 60 dep[S] = 1; 61 while(!q.empty()){ 62 int t = q.front(); 63 q.pop(); 64 for(int i = head[t] ; i ; i = Ed[i].upEd) 65 if(Ed[i].f && !dep[Ed[i].end]){ 66 dep[Ed[i].end] = dep[t] + 1; 67 if(Ed[i].end == T){ 68 memcpy(cur , head , sizeof(head)); 69 return 1; 70 } 71 q.push(Ed[i].end); 72 } 73 } 74 return 0; 75 } 76 77 inline int dfs(int x , int mF){ 78 if(x == T) 79 return mF; 80 int sum = 0; 81 for(int &i = cur[x] ; i ; i = Ed[i].upEd) 82 if(Ed[i].f && dep[Ed[i].end] == dep[x] + 1){ 83 int t = dfs(Ed[i].end , min(mF - sum , Ed[i].f)); 84 if(t){ 85 Ed[i].f -= t; 86 Ed[i ^ 1].f += t; 87 sum += t; 88 if(sum == mF) 89 break; 90 } 91 } 92 return sum; 93 } 94 95 int Dinic(){ 96 int ans = 0; 97 while(bfs()) 98 ans += dfs(S , INF); 99 return ans;100 }101 102 inline bool SPFA(){103 memset(dis , 0x3f , sizeof(dis));104 dis[S] = 0;105 while(!q.empty())106 q.pop();107 q.push(S);108 flo[S] = INF;109 while(!q.empty()){110 int t = q.front();111 q.pop();112 vis[t] = 0;113 for(int i = head[t] ; i ; i = Ed[i].upEd)114 if(Ed[i].f && dis[Ed[i].end] > dis[t] + Ed[i].c){115 dis[Ed[i].end] = dis[t] + Ed[i].c;116 flo[Ed[i].end] = min(Ed[i].f , flo[t]);117 pre[Ed[i].end] = i;118 if(!vis[Ed[i].end]){119 vis[Ed[i].end] = 1;120 q.push(Ed[i].end);121 }122 }123 }124 return dis[T] != dis[T + 1];125 }126 127 int EK(){128 int ans = 0;129 while(SPFA()){130 int cur = T , sum = 0;131 while(cur != S){132 sum += Ed[pre[cur]].c;133 Ed[pre[cur]].f -= flo[T];134 Ed[pre[cur] ^ 1].f += flo[T];135 cur = Ed[pre[cur] ^ 1].end;136 }137 ans += sum * flo[T];138 }139 return ans;140 }141 142 bool in[MAXN];143 int nxt[MAXN];144 145 int main(){146 #ifndef ONLINE_JUDGE147 freopen("in" , "r" , stdin);148 //freopen("out" , "w" , stdout);149 #endif150 N = read();151 M = read();152 T = 2 * N + 1;153 for(int i = 1 ; i <= N ; ++i){154 addEd(S , i + N , 1);155 addEd(i + N , S , 0);156 addEd(i , T , 1);157 addEd(T , i , 0);158 }159 for(int i = 1 ; i <= M ; ++i){160 int a = read() , b = read();161 addEd(a + N , b , 1);162 addEd(b , a + N , 0);163 }164 int ans = N - Dinic();165 for(int i = head[S] ; i ; i = Ed[i].upEd)166 if(!Ed[i].f)167 for(int j = head[Ed[i].end] ; j ; j = Ed[j].upEd)168 if(!Ed[j].f){169 nxt[Ed[i].end - N] = Ed[j].end;170 in[Ed[j].end] = 1;171 break;172 }173 for(int i = 1 ; i <= N ; ++i)174 if(!in[i]){175 int t = i;176 while(t){177 cout << t << ' ';178 t = nxt[t];179 }180 cout << endl;181 }182 cout << ans;183 return 0;184 }
最小路径覆盖

按照题目给出的图片黑白染色,发现限制条件和点之间变成了一个二分图。

所以要求二分图最大独立集,同方格取数问题。

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #define INF 0x3f3f3f3f 17 //This code is written by Itst 18 using namespace std; 19 20 inline int read(){ 21 int a = 0; 22 char c = getchar(); 23 bool f = 0; 24 while(!isdigit(c) && c != EOF){ 25 if(c == '-') 26 f = 1; 27 c = getchar(); 28 } 29 if(c == EOF) 30 exit(0); 31 while(isdigit(c)){ 32 a = (a << 3) + (a << 1) + (c ^ '0'); 33 c = getchar(); 34 } 35 return f ? -a : a; 36 } 37 38 const int MAXN = 4e4 + 7 , MAXM = 1e6 + 7; 39 struct Edge{ 40 int end , upEd , f , c; 41 }Ed[MAXM]; 42 int head[MAXN] , cur[MAXN] , dep[MAXN]; 43 int N , M , S , T , cntEd = 1; 44 bool vis[MAXN]; 45 queue < int > q; 46 47 inline void addEd(int a , int b , int c , int d = 0){ 48 Ed[++cntEd].end = b; 49 Ed[cntEd].upEd = head[a]; 50 Ed[cntEd].f = c; 51 Ed[cntEd].c = d; 52 head[a] = cntEd; 53 } 54 55 inline bool bfs(){ 56 while(!q.empty()) 57 q.pop(); 58 q.push(S); 59 memset(dep , 0 , sizeof(dep)); 60 dep[S] = 1; 61 while(!q.empty()){ 62 int t = q.front(); 63 q.pop(); 64 for(int i = head[t] ; i ; i = Ed[i].upEd) 65 if(Ed[i].f && !dep[Ed[i].end]){ 66 dep[Ed[i].end] = dep[t] + 1; 67 if(Ed[i].end == T){ 68 memcpy(cur , head , sizeof(head)); 69 return 1; 70 } 71 q.push(Ed[i].end); 72 } 73 } 74 return 0; 75 } 76 77 inline int dfs(int x , int mF){ 78 if(x == T) 79 return mF; 80 int sum = 0; 81 for(int &i = cur[x] ; i ; i = Ed[i].upEd) 82 if(Ed[i].f && dep[Ed[i].end] == dep[x] + 1){ 83 int t = dfs(Ed[i].end , min(mF - sum , Ed[i].f)); 84 if(t){ 85 Ed[i].f -= t; 86 Ed[i ^ 1].f += t; 87 sum += t; 88 if(sum == mF) 89 break; 90 } 91 } 92 return sum; 93 } 94 95 int Dinic(){ 96 int ans = 0; 97 while(bfs()) 98 ans += dfs(S , INF); 99 return ans;100 }101 102 #define id(i,j) (((i) - 1) * N + (j))103 const int dir[8][2] = { 1,2,1,-2,2,1,2,-1,-1,-2,-1,2,-2,-1,-2,1};104 bool ban[210][210];105 106 int main(){107 #ifndef ONLINE_JUDGE108 freopen("in" , "r" , stdin);109 //freopen("out" , "w" , stdout);110 #endif111 N = read();112 M = read();113 T = N * N + 1;114 for(int i = 1 ; i <= M ; ++i){115 int a = read() , b = read();116 ban[a][b] = 1;117 }118 for(int i = 1 ; i <= N ; ++i)119 for(int j = 1 ; j <= N ; ++j)120 if(!ban[i][j])121 if((i + j) & 1){122 addEd(S , id(i , j) , 1);123 addEd(id(i , j) , S , 0);124 for(int k = 0 ; k < 8 ; ++k){125 int p = i + dir[k][0] , q = j + dir[k][1];126 if(p > 0 && p <= N && q > 0 && q <= N && !ban[p][q]){127 addEd(id(i , j) , id(p , q) , 1);128 addEd(id(p , q) , id(i , j) , 0);129 }130 }131 }132 else{133 addEd(id(i , j) , T , 1);134 addEd(T , id(i , j) , 0);135 }136 cout << N * N - M - Dinic();137 return 0;138 }
骑士共存

费用流同深海机器人问题

输出方案直接在反边上暴搜

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #define INF 0x3f3f3f3f 17 //This code is written by Itst 18 using namespace std; 19 20 inline int read(){ 21 int a = 0; 22 char c = getchar(); 23 bool f = 0; 24 while(!isdigit(c) && c != EOF){ 25 if(c == '-') 26 f = 1; 27 c = getchar(); 28 } 29 if(c == EOF) 30 exit(0); 31 while(isdigit(c)){ 32 a = (a << 3) + (a << 1) + (c ^ '0'); 33 c = getchar(); 34 } 35 return f ? -a : a; 36 } 37 38 const int MAXN = 5010 , MAXM = 100010; 39 struct Edge{ 40 int end , upEd , f , c; 41 }Ed[MAXM]; 42 int head[MAXN]; 43 int N , M , K , S , T , cntEd = 1; 44 queue < int > q; 45 46 inline void addEd(int a , int b , int c , int d = 0){ 47 Ed[++cntEd].end = b; 48 Ed[cntEd].upEd = head[a]; 49 Ed[cntEd].f = c; 50 Ed[cntEd].c = d; 51 head[a] = cntEd; 52 } 53 54 bool vis[MAXN]; 55 int dis[MAXN] , pre[MAXN] , flo[MAXN]; 56 57 inline bool SPFA(){ 58 memset(dis , -0x3f , sizeof(dis)); 59 dis[S] = 0; 60 while(!q.empty()) 61 q.pop(); 62 q.push(S); 63 flo[S] = INF; 64 while(!q.empty()){ 65 int t = q.front(); 66 q.pop(); 67 vis[t] = 0; 68 for(int i = head[t] ; i ; i = Ed[i].upEd) 69 if(Ed[i].f && dis[Ed[i].end] < dis[t] + Ed[i].c){ 70 dis[Ed[i].end] = dis[t] + Ed[i].c; 71 flo[Ed[i].end] = min(Ed[i].f , flo[t]); 72 pre[Ed[i].end] = i; 73 if(!vis[Ed[i].end]){ 74 vis[Ed[i].end] = 1; 75 q.push(Ed[i].end); 76 } 77 } 78 } 79 return dis[T] != dis[T + 1]; 80 } 81 82 void EK(){ 83 while(SPFA()){ 84 int cur = T , sum = 0; 85 while(cur != S){ 86 sum += Ed[pre[cur]].c; 87 Ed[pre[cur]].f -= flo[T]; 88 Ed[pre[cur] ^ 1].f += flo[T]; 89 cur = Ed[pre[cur] ^ 1].end; 90 } 91 } 92 } 93 94 #define id(i , j , k) (((i) - 1) * M + (j) + (k) * N * M) 95 96 int cnt = 0; 97 int search(int x , int minN){ 98 if(x == S){ 99 ++cnt;100 return minN;101 }102 for(int &i = head[x] ; i ; i = Ed[i].upEd)103 if((i & 1) && Ed[i].f){104 int t = search(Ed[i].end , min(Ed[i].f , minN));105 if(t){106 Ed[i].f -= t;107 if(Ed[i].end > N * M && x <= N * M)108 cout << cnt << ' ' << (x - Ed[i].end + N * M == 1) << endl;109 return t;110 }111 }112 return 0; 113 }114 115 int main(){116 #ifndef ONLINE_JUDGE117 freopen("in" , "r" , stdin);118 //freopen("out" , "w" , stdout);119 #endif120 K = read();121 M = read();122 N = read();123 T = N * M * 2 + 1;124 addEd(S , id(1 , 1 , 0) , K);125 addEd(id(1 , 1 , 0) , S , 0);126 addEd(id(N , M , 1) , T , K);127 addEd(T , id(N , M , 1) , 0);128 for(int i = 1 ; i <= N ; ++i)129 for(int j = 1 ; j <= M ; ++j){130 switch(read()){131 case 2:132 addEd(id(i , j , 0) , id(i , j , 1) , 1 , 1);133 addEd(id(i , j , 1) , id(i , j , 0) , 0 , -1);134 case 0:135 addEd(id(i , j , 0) , id(i , j , 1) , INF);136 addEd(id(i , j , 1) , id(i , j , 0) , 0);137 break;138 }139 }140 for(int i = 1 ; i <= N ; ++i)141 for(int j = 1 ; j <= M ; ++j){142 if(i != 1){143 addEd(id(i - 1 , j , 1) , id(i , j , 0) , INF);144 addEd(id(i , j , 0) , id(i - 1 , j , 1) , 0);145 }146 if(j != 1){147 addEd(id(i , j - 1 , 1) , id(i , j , 0) , INF);148 addEd(id(i , j , 0) , id(i , j - 1 , 1) , 0);149 }150 }151 EK();152 while(search(T , INF));153 return 0;154 }
火星探险

状压最短路

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 //This code is written by Itst17 using namespace std;18 19 inline int read(){20 int a = 0;21 char c = getchar();22 bool f = 0;23 while(!isdigit(c) && c != EOF){24 if(c == '-')25 f = 1;26 c = getchar();27 }28 if(c == EOF)29 exit(0);30 while(isdigit(c)){31 a = a * 10 + c - 48;32 c = getchar();33 }34 return f ? -a : a;35 }36 37 const int dir[4][2] = { 0,1,0,-1,1,0,-1,0};38 int D[11][11][4] , K[11][11];39 bool vis[11][11][1 << 10];40 int N , M , P;41 struct zt{42 int x , y , k , st;43 }now;44 queue < zt > Q;45 46 void bfs(){47 vis[1][1][K[1][1]] = 1;48 Q.push((zt){ 1 , 1 , K[1][1] , 0});49 while(!Q.empty()){50 now = Q.front();51 Q.pop();52 if(now.x == N && now.y == M){53 cout << now.st;54 exit(0);55 }56 for(int i = 0 ; i < 4 ; ++i){57 int p = now.x + dir[i][0] , q = now.y + dir[i][1];58 if(p > 0 && p <= N && q > 0 && q <= M)59 if((now.k & D[now.x][now.y][i]) == D[now.x][now.y][i])60 if(!vis[p][q][now.k | K[p][q]]){61 vis[p][q][now.k | K[p][q]] = 1;62 Q.push((zt){p , q , now.k | K[p][q] , now.st + 1});63 }64 }65 }66 }67 68 int main(){69 #ifndef ONLINE_JUDGE70 freopen("in","r",stdin);71 //freopen("out","w",stdout);72 #endif73 N = read();74 M = read();75 P = read();76 for(int K = read() ; K ; --K){77 int x1 = read() , y1 = read() , x2 = read() , y2 = read() , G = read();78 if(x1 == x2){79 if(y1 > y2)80 swap(y1 , y2);81 D[x1][y1][0] |= 1 << G;82 D[x1][y2][1] |= 1 << G;83 }84 else{85 if(x1 > x2)86 swap(x1 , x2);87 D[x1][y1][2] |= 1 << G;88 D[x2][y2][3] |= 1 << G;89 }90 }91 for(int Q = read() ; Q ; --Q){92 int x = read() , y = read() , k = read();93 K[x][y] |= 1 << k;94 }95 bfs();96 puts("-1");97 return 0;98 }
孤岛营救

按照给的条件建图然后费用流即可

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #define INF 0x3f3f3f3f 17 //This code is written by Itst 18 using namespace std; 19 20 inline int read(){ 21 int a = 0; 22 char c = getchar(); 23 bool f = 0; 24 while(!isdigit(c) && c != EOF){ 25 if(c == '-') 26 f = 1; 27 c = getchar(); 28 } 29 if(c == EOF) 30 exit(0); 31 while(isdigit(c)){ 32 a = (a << 3) + (a << 1) + (c ^ '0'); 33 c = getchar(); 34 } 35 return f ? -a : a; 36 } 37 38 const int MAXN = 1e5 + 7 , MAXM = 1e6 + 7; 39 struct Edge{ 40 int end , upEd , f , c; 41 }Ed[MAXM]; 42 int head[MAXN]; 43 int N , M , S , T , cntEd = 1; 44 queue < int > q; 45 46 inline void addEd(int a , int b , int c , int d = 0){ 47 Ed[++cntEd].end = b; 48 Ed[cntEd].upEd = head[a]; 49 Ed[cntEd].f = c; 50 Ed[cntEd].c = d; 51 head[a] = cntEd; 52 } 53 54 bool vis[MAXN]; 55 int dis[MAXN] , pre[MAXN] , flo[MAXN];; 56 57 inline bool SPFA(){ 58 memset(dis , -0x3f , sizeof(dis)); 59 dis[S] = 0; 60 while(!q.empty()) 61 q.pop(); 62 q.push(S); 63 flo[S] = INF; 64 while(!q.empty()){ 65 int t = q.front(); 66 q.pop(); 67 vis[t] = 0; 68 for(int i = head[t] ; i ; i = Ed[i].upEd) 69 if(Ed[i].f && dis[Ed[i].end] < dis[t] + Ed[i].c){ 70 dis[Ed[i].end] = dis[t] + Ed[i].c; 71 flo[Ed[i].end] = min(Ed[i].f , flo[t]); 72 pre[Ed[i].end] = i; 73 if(!vis[Ed[i].end]){ 74 vis[Ed[i].end] = 1; 75 q.push(Ed[i].end); 76 } 77 } 78 } 79 return dis[T] != dis[T + 1]; 80 } 81 82 int EK(){ 83 int ans = 0; 84 while(SPFA()){ 85 int cur = T , sum = 0; 86 while(cur != S){ 87 sum += Ed[pre[cur]].c; 88 Ed[pre[cur]].f -= flo[T]; 89 Ed[pre[cur] ^ 1].f += flo[T]; 90 cur = Ed[pre[cur] ^ 1].end; 91 } 92 ans += sum * flo[T]; 93 } 94 return ans; 95 } 96 97 int num[21][41] , dir[21][41] , all; 98 99 void add1(){100 for(int i = 1 ; i <= M ; ++i){101 addEd(S , dir[1][i] , 1);102 addEd(dir[1][i] , S , 0);103 }104 for(int i = 1 ; i < N ; ++i)105 for(int j = 1 ; j <= M + i - 1 ; ++j){106 addEd(dir[i][j] + all , dir[i + 1][j] , 1);107 addEd(dir[i + 1][j] , dir[i][j] + all , 0);108 addEd(dir[i][j] + all , dir[i + 1][j + 1] , 1);109 addEd(dir[i + 1][j + 1] , dir[i][j] + all , 0);110 }111 for(int i = 1 ; i <= N + M - 1 ; ++i){112 addEd(dir[N][i] + all , T , INF);113 addEd(T , dir[N][i] + all , 0);114 }115 for(int i = 1 ; i <= N ; ++i)116 for(int j = 1 ; j <= M + i - 1 ; ++j){117 addEd(dir[i][j] , dir[i][j] + all , 1 , num[i][j]);118 addEd(dir[i][j] + all , dir[i][j] , 0 , -num[i][j]);119 }120 }121 122 void add2(){123 memset(head , 0 , sizeof(head));124 cntEd = 1;125 add1();126 for(int i = 1 ; i <= N ; ++i)127 for(int j = 1 ; j <= M + i - 1 ; ++j){128 addEd(dir[i][j] , dir[i][j] + all , INF , num[i][j]);129 addEd(dir[i][j] + all , dir[i][j] , 0 , -num[i][j]);130 }131 }132 133 void add3(){134 add2();135 for(int i = 1 ; i < N ; ++i)136 for(int j = 1 ; j <= M + i - 1 ; ++j){137 addEd(dir[i][j] + all , dir[i + 1][j] , INF);138 addEd(dir[i + 1][j] , dir[i][j] + all , 0);139 addEd(dir[i][j] + all , dir[i + 1][j + 1] , INF);140 addEd(dir[i + 1][j + 1] , dir[i][j] + all , 0);141 }142 }143 144 int main(){145 #ifndef ONLINE_JUDGE146 freopen("in" , "r" , stdin);147 //freopen("out" , "w" , stdout);148 #endif149 M = read();150 N = read();151 for(int i = 1 ; i <= N ; ++i)152 for(int j = 1 ; j <= i + M - 1 ; ++j){153 num[i][j] = read();154 dir[i][j] = ++all;155 }156 T = all * 2 + 1;157 add1();158 cout << EK() << endl;159 add2();160 cout << EK() << endl;161 add3();162 cout << EK() << endl;163 return 0;164 }
数字梯形

可以发现这是一个最小路径覆盖问题的翻版,限定总路径数求最大点数

每一次加入一个球,考虑是否存在$S$到$T$的流

对于每一个数$i$,拆成$A_i,B_i$,$S->B_i$流量为$1$,$A_i->T$流量为$1$,$B_i->T'$流量为$1$,$T'->T$流量为$K$,和为平方数的两个数$i,j(i>j)$之间建边$B_i->A_j$流量为$1$

在残量网络上若一条边$B_i->A_j$满流表示$i$在$j$上面,$T'$点用来限制柱子数量

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #define INF 0x3f3f3f3f 17 //This code is written by Itst 18 using namespace std; 19 20 inline int read(){ 21 int a = 0; 22 char c = getchar(); 23 bool f = 0; 24 while(!isdigit(c) && c != EOF){ 25 if(c == '-') 26 f = 1; 27 c = getchar(); 28 } 29 if(c == EOF) 30 exit(0); 31 while(isdigit(c)){ 32 a = (a << 3) + (a << 1) + (c ^ '0'); 33 c = getchar(); 34 } 35 return f ? -a : a; 36 } 37 38 const int MAXN = 1e5 + 7 , MAXM = 1e6 + 7; 39 struct Edge{ 40 int end , upEd , f , c; 41 }Ed[MAXM]; 42 int head[MAXN]; 43 int N , M , S , T , cntEd = 1; 44 queue < int > q; 45 46 inline void addEd(int a , int b , int c , int d = 0){ 47 Ed[++cntEd].end = b; 48 Ed[cntEd].upEd = head[a]; 49 Ed[cntEd].f = c; 50 Ed[cntEd].c = d; 51 head[a] = cntEd; 52 } 53 54 int cur[MAXN] , dep[MAXN]; 55 56 inline bool bfs(){ 57 while(!q.empty()) 58 q.pop(); 59 q.push(S); 60 memset(dep , 0 , sizeof(dep)); 61 dep[S] = 1; 62 while(!q.empty()){ 63 int t = q.front(); 64 q.pop(); 65 for(int i = head[t] ; i ; i = Ed[i].upEd) 66 if(Ed[i].f && !dep[Ed[i].end]){ 67 dep[Ed[i].end] = dep[t] + 1; 68 if(Ed[i].end == T){ 69 memcpy(cur , head , sizeof(head)); 70 return 1; 71 } 72 q.push(Ed[i].end); 73 } 74 } 75 return 0; 76 } 77 78 inline int dfs(int x , int mF){ 79 if(x == T) 80 return mF; 81 int sum = 0; 82 for(int &i = cur[x] ; i ; i = Ed[i].upEd) 83 if(Ed[i].f && dep[Ed[i].end] == dep[x] + 1){ 84 int t = dfs(Ed[i].end , min(mF - sum , Ed[i].f)); 85 if(t){ 86 Ed[i].f -= t; 87 Ed[i ^ 1].f += t; 88 sum += t; 89 if(sum == mF) 90 break; 91 } 92 } 93 return sum; 94 } 95 96 int Dinic(){ 97 int ans = 0; 98 while(bfs()) 99 ans += dfs(S , INF);100 return ans;101 }102 103 int nxt[MAXN];104 bool in[MAXN];105 106 void output(int x){107 if(nxt[x])108 output(nxt[x]);109 cout << x << ' ';110 }111 112 int main(){113 #ifndef ONLINE_JUDGE114 freopen("in" , "r" , stdin);115 //freopen("out" , "w" , stdout);116 #endif117 T = 1;118 int tmp = 2 , cur = 2 , cnt = 0;119 addEd(tmp , T , read());120 addEd(T , tmp , 0);121 do{122 ++cnt;123 cur += 2;124 addEd(S , cur , 1);125 addEd(cur , S , 0);126 addEd(cur - 1 , T , 1);127 addEd(T , cur - 1 , 0);128 addEd(cur , tmp , 1);129 addEd(tmp , cur , 0);130 for(int i = 1 ; i < cnt ; ++i){131 int t = i + cnt;132 if((int)sqrt(t) * (int)sqrt(t) == t){133 addEd(cur , i * 2 + 1 , 1);134 addEd(i * 2 + 1 , cur , 0);135 }136 }137 }while(Dinic());138 cout << cnt - 1 << endl;139 for(int i = 1 ; i < cnt ; ++i)140 for(int j = head[i * 2 + 2] ; j ; j = Ed[j].upEd)141 if(Ed[j].end > 2 && !Ed[j].f){142 nxt[i] = Ed[j].end / 2;143 in[Ed[j].end / 2] = 1;144 break;145 }146 for(int i = 1 ; i < cnt ; ++i)147 if(!in[i]){148 output(i);149 putchar('\n');150 }151 return 0;152 }
魔术球

与原题等价的题意是:从$1$到$N$找两条除起终点外不相交的路径使得经过的点数最多

拆点费用流即可

1 // luogu-judger-enable-o2  2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #define INF 0x3f3f3f3f 18 //This code is written by Itst 19 using namespace std; 20 21 inline int read(){ 22 int a = 0; 23 char c = getchar(); 24 bool f = 0; 25 while(!isdigit(c) && c != EOF){ 26 if(c == '-') 27 f = 1; 28 c = getchar(); 29 } 30 if(c == EOF) 31 exit(0); 32 while(isdigit(c)){ 33 a = (a << 3) + (a << 1) + (c ^ '0'); 34 c = getchar(); 35 } 36 return f ? -a : a; 37 } 38 39 const int MAXN = 1e5 + 7 , MAXM = 1e6 + 7; 40 struct Edge{ 41 int end , upEd , f , c; 42 }Ed[MAXM]; 43 int head[MAXN]; 44 int N , M , S , T , cntEd = 1; 45 queue < int > q; 46 47 inline void addEd(int a , int b , int c , int d = 0){ 48 Ed[++cntEd].end = b; 49 Ed[cntEd].upEd = head[a]; 50 Ed[cntEd].f = c; 51 Ed[cntEd].c = d; 52 head[a] = cntEd; 53 } 54 55 bool vis[MAXN]; 56 int dis[MAXN] , pre[MAXN] , flo[MAXN];; 57 58 inline bool SPFA(){ 59 memset(dis , -0x3f , sizeof(dis)); 60 dis[S] = 0; 61 while(!q.empty()) 62 q.pop(); 63 q.push(S); 64 flo[S] = INF; 65 while(!q.empty()){ 66 int t = q.front(); 67 q.pop(); 68 vis[t] = 0; 69 for(int i = head[t] ; i ; i = Ed[i].upEd) 70 if(Ed[i].f && dis[Ed[i].end] < dis[t] + Ed[i].c){ 71 dis[Ed[i].end] = dis[t] + Ed[i].c; 72 flo[Ed[i].end] = min(Ed[i].f , flo[t]); 73 pre[Ed[i].end] = i; 74 if(!vis[Ed[i].end]){ 75 vis[Ed[i].end] = 1; 76 q.push(Ed[i].end); 77 } 78 } 79 } 80 return dis[T] != dis[T + 1]; 81 } 82 83 int EK(){ 84 int ans = 0; 85 while(SPFA()){ 86 int cur = T , sum = 0; 87 while(cur != S){ 88 sum += Ed[pre[cur]].c; 89 Ed[pre[cur]].f -= flo[T]; 90 Ed[pre[cur] ^ 1].f += flo[T]; 91 cur = Ed[pre[cur] ^ 1].end; 92 } 93 ans += sum * flo[T]; 94 } 95 return ans; 96 } 97 98 string s , city[MAXN]; 99 map < string , int > lsh;100 101 int main(){102 #ifndef ONLINE_JUDGE103 freopen("in" , "r" , stdin);104 //freopen("out" , "w" , stdout);105 #endif106 N = read();107 M = read();108 T = N * 2 + 1;109 addEd(0 , N + 1 , 2);110 addEd(N + 1 , 0 , 0);111 addEd(N , T , 2);112 addEd(T , N , 0);113 for(int i = 1 ; i <= N ; ++i){114 addEd(i , i + N , 1 , 1);115 addEd(i + N , i , 0 , -1);116 cin >> city[i];117 lsh[city[i]] = i;118 }119 for(int i = 1 ; i <= M ; ++i){120 cin >> s;121 int a = lsh[s];122 cin >> s;123 int b = lsh[s];124 if(a > b)125 swap(a , b);126 addEd(a + N , b , 2);127 addEd(b , a + N , 0);128 }129 int t = EK();130 if(Ed[2].f)131 puts("No Solution!");132 else{133 cout << t + 2 << endl;134 cout << city[1] << endl;135 int cur = N + 1;136 while(cur != T)137 for(int i = head[cur] ; i ; i = Ed[i].upEd)138 if(!(i & 1) && Ed[i ^ 1].f){139 --Ed[i ^ 1].f;140 cur = Ed[i].end;141 if(cur <= N)142 cout << city[cur] << endl;143 break;144 }145 cur = N;146 while(cur != N + 1)147 for(int i = head[cur] ; i ; i = Ed[i].upEd)148 if((i & 1) && Ed[i].f){149 cur = Ed[i].end;150 if(cur <= N)151 cout << city[cur] << endl;152 break;153 }154 cout << city[1] << endl;155 }156 return 0;157 }
航空路线

判断无解用并查集

第二问考虑二分

设$mid$为当前二分的答案,则将所有星球拆成$mid+1$个点表示每个星球在$0,1,2...mid$时刻的状态

如果使用Dinic,则枚举时间、每一次加点会更快

1 // luogu-judger-enable-o2  2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #define INF 0x3f3f3f3f 18 //This code is written by Itst 19 using namespace std; 20 21 inline int read(){ 22 int a = 0; 23 char c = getchar(); 24 bool f = 0; 25 while(!isdigit(c) && c != EOF){ 26 if(c == '-') 27 f = 1; 28 c = getchar(); 29 } 30 if(c == EOF) 31 exit(0); 32 while(isdigit(c)){ 33 a = (a << 3) + (a << 1) + (c ^ '0'); 34 c = getchar(); 35 } 36 return f ? -a : a; 37 } 38 39 const int MAXN = 1e5 + 7 , MAXM = 1e6 + 7; 40 struct Edge{ 41 int end , upEd , f , c; 42 }Ed[MAXM]; 43 int head[MAXN]; 44 int N , M , S , T , cntEd = 1; 45 queue < int > q; 46 47 inline void addEd(int a , int b , int c , int d = 0){ 48 Ed[++cntEd].end = b; 49 Ed[cntEd].upEd = head[a]; 50 Ed[cntEd].f = c; 51 Ed[cntEd].c = d; 52 head[a] = cntEd; 53 } 54 55 int cur[MAXN] , dep[MAXN]; 56 57 inline bool bfs(){ 58 while(!q.empty()) 59 q.pop(); 60 q.push(S); 61 memset(dep , 0 , sizeof(dep)); 62 dep[S] = 1; 63 while(!q.empty()){ 64 int t = q.front(); 65 q.pop(); 66 for(int i = head[t] ; i ; i = Ed[i].upEd) 67 if(Ed[i].f && !dep[Ed[i].end]){ 68 dep[Ed[i].end] = dep[t] + 1; 69 if(Ed[i].end == T){ 70 memcpy(cur , head , sizeof(head)); 71 return 1; 72 } 73 q.push(Ed[i].end); 74 } 75 } 76 return 0; 77 } 78 79 inline int dfs(int x , int mF){ 80 if(x == T) 81 return mF; 82 int sum = 0; 83 for(int &i = cur[x] ; i ; i = Ed[i].upEd) 84 if(Ed[i].f && dep[Ed[i].end] == dep[x] + 1){ 85 int t = dfs(Ed[i].end , min(mF - sum , Ed[i].f)); 86 if(t){ 87 Ed[i].f -= t; 88 Ed[i ^ 1].f += t; 89 sum += t; 90 if(sum == mF) 91 break; 92 } 93 } 94 return sum; 95 } 96 97 int Dinic(){ 98 int ans = 0; 99 while(bfs())100 ans += dfs(S , INF);101 return ans;102 }103 104 int H[21] , P[21] , st[21][81] , fa[81];105 106 int find(int x){107 return fa[x] == x ? x : (fa[x] = find(fa[x]));108 }109 110 int main(){111 #ifndef ONLINE_JUDGE112 freopen("in" , "r" , stdin);113 //freopen("out" , "w" , stdout);114 #endif115 N = read() + 1;116 M = read();117 int K = read();118 for(int i = 1 ; i <= N ; ++i)119 fa[i] = i;120 for(int i = 1 ; i <= M ; ++i){121 H[i] = read();122 P[i] = read();123 for(int j = 0 ; j < P[i] ; ++j)124 st[i][j] = read() + 1;125 for(int j = 1 ; j < P[i] ; ++j)126 fa[find(st[i][j])] = find(st[i][j - 1]);127 }128 if(find(1) != find(0))129 puts("0");130 else{131 ++N;132 T = 0;133 S = 1;134 int cnt = 0;135 while((K -= Dinic()) > 0){136 ++cnt;137 for(int i = 1 ; i <= M ; ++i){138 addEd(st[i][(cnt - 1) % P[i]] + (cnt - 1) * N , st[i][cnt % P[i]] + cnt * N , H[i]);139 addEd(st[i][cnt % P[i]] + cnt * N , st[i][(cnt - 1) % P[i]] + (cnt - 1) * N , 0);140 }141 for(int i = 1 ; i < N ; ++i){142 addEd(i + (cnt - 1) * N , i + cnt * N , INF);143 addEd(i + cnt * N , i + (cnt - 1) * N , 0);144 }145 addEd(N * cnt , T , INF);146 addEd(T , N * cnt , 0);147 }148 cout << cnt;149 }150 return 0;151 }
家园/星际转移

原题的等价题意:取$K$个区间集,每个区间只能在所有区间集中最多出现一次,且满足每个区间集内区间两两不交,求最长的区间集长度之和

建立费用流模型:数轴上每个整点$i$对应网络流中的点$i$:$i->i+1$,流量$K$费用$0$;对于区间$(l_i,r_i)$,$l_i -> r_i$,流量$1$费用$r_i - l_i$。

那么每一次增广都意味着在剩余没有被选中的区间中选择一些区间,成为一个新的区间集。

离散化、跑最大费用最大流即可

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #define INF 0x3f3f3f3f 17 //This code is written by Itst 18 using namespace std; 19 20 inline int read(){ 21 int a = 0; 22 char c = getchar(); 23 bool f = 0; 24 while(!isdigit(c) && c != EOF){ 25 if(c == '-') 26 f = 1; 27 c = getchar(); 28 } 29 if(c == EOF) 30 exit(0); 31 while(isdigit(c)){ 32 a = (a << 3) + (a << 1) + (c ^ '0'); 33 c = getchar(); 34 } 35 return f ? -a : a; 36 } 37 38 const int MAXN = 1e5 + 7 , MAXM = 1e6 + 7; 39 struct Edge{ 40 int end , upEd , f , c; 41 }Ed[MAXM]; 42 int head[MAXN]; 43 int N , M , S , T , cntEd = 1; 44 queue < int > q; 45 46 inline void addEd(int a , int b , int c , int d = 0){ 47 Ed[++cntEd].end = b; 48 Ed[cntEd].upEd = head[a]; 49 Ed[cntEd].f = c; 50 Ed[cntEd].c = d; 51 head[a] = cntEd; 52 } 53 54 bool vis[MAXN]; 55 int dis[MAXN] , pre[MAXN] , flo[MAXN];; 56 57 inline bool SPFA(){ 58 memset(dis , -0x3f , sizeof(dis)); 59 dis[S] = 0; 60 while(!q.empty()) 61 q.pop(); 62 q.push(S); 63 flo[S] = INF; 64 while(!q.empty()){ 65 int t = q.front(); 66 q.pop(); 67 vis[t] = 0; 68 for(int i = head[t] ; i ; i = Ed[i].upEd) 69 if(Ed[i].f && dis[Ed[i].end] < dis[t] + Ed[i].c){ 70 dis[Ed[i].end] = dis[t] + Ed[i].c; 71 flo[Ed[i].end] = min(Ed[i].f , flo[t]); 72 pre[Ed[i].end] = i; 73 if(!vis[Ed[i].end]){ 74 vis[Ed[i].end] = 1; 75 q.push(Ed[i].end); 76 } 77 } 78 } 79 return dis[T] != dis[T + 1]; 80 } 81 82 int EK(){ 83 int ans = 0; 84 while(SPFA()){ 85 int cur = T , sum = 0; 86 while(cur != S){ 87 sum += Ed[pre[cur]].c; 88 Ed[pre[cur]].f -= flo[T]; 89 Ed[pre[cur] ^ 1].f += flo[T]; 90 cur = Ed[pre[cur] ^ 1].end; 91 } 92 ans += sum * flo[T]; 93 } 94 return ans; 95 } 96 97 int lsh[MAXN] , L[MAXN][2] , cntL; 98 99 int main(){100 #ifndef ONLINE_JUDGE101 freopen("in" , "r" , stdin);102 //freopen("out" , "w" , stdout);103 #endif104 N = read();105 M = read();106 for(int i = 1 ; i <= N ; ++i){107 lsh[++cntL] = L[i][0] = read();108 lsh[++cntL] = L[i][1] = read();109 }110 sort(lsh + 1 , lsh + cntL + 1);111 cntL = unique(lsh + 1 , lsh + cntL + 1) - lsh - 1;112 T = cntL + 1;113 for(int i = 0 ; i <= cntL ; ++i){114 addEd(i , i + 1 , M);115 addEd(i + 1 , i , 0);116 }117 for(int i = 1 ; i <= N ; ++i){118 L[i][0] = lower_bound(lsh + 1 , lsh + cntL + 1 , L[i][0]) - lsh;119 L[i][1] = lower_bound(lsh + 1 , lsh + cntL + 1 , L[i][1]) - lsh;120 addEd(L[i][0] , L[i][1] , 1 , lsh[L[i][1]] - lsh[L[i][0]]);121 addEd(L[i][1] , L[i][0] , 0 , lsh[L[i][0]] - lsh[L[i][1]]);122 }123 cout << EK();124 return 0;125 }
最长K可重区间集

同最长K可重区间集

值得注意的是有可能有线段$(x_1,y_1),(x_2,y_2)$满足$x_1=x_2$,所以对于每一个数轴上的整点$i$需要拆成两个点$A_i,B_i$,$A_i->B_i$表示覆盖点$i$

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #define INF 0x3f3f3f3f 17 //This code is written by Itst 18 using namespace std; 19 20 inline int read(){ 21 int a = 0; 22 char c = getchar(); 23 bool f = 0; 24 while(!isdigit(c) && c != EOF){ 25 if(c == '-') 26 f = 1; 27 c = getchar(); 28 } 29 if(c == EOF) 30 exit(0); 31 while(isdigit(c)){ 32 a = (a << 3) + (a << 1) + (c ^ '0'); 33 c = getchar(); 34 } 35 return f ? -a : a; 36 } 37 38 const int MAXN = 1e5 + 7 , MAXM = 1e6 + 7; 39 struct Edge{ 40 int end , upEd , f , c; 41 }Ed[MAXM]; 42 int head[MAXN]; 43 int N , M , S , T , cntEd = 1; 44 queue < int > q; 45 46 inline void addEd(int a , int b , int c , int d = 0){ 47 Ed[++cntEd].end = b; 48 Ed[cntEd].upEd = head[a]; 49 Ed[cntEd].f = c; 50 Ed[cntEd].c = d; 51 head[a] = cntEd; 52 } 53 54 bool vis[MAXN]; 55 int dis[MAXN] , pre[MAXN] , flo[MAXN];; 56 57 inline bool SPFA(){ 58 memset(dis , -0x3f , sizeof(dis)); 59 dis[S] = 0; 60 while(!q.empty()) 61 q.pop(); 62 q.push(S); 63 flo[S] = INF; 64 while(!q.empty()){ 65 int t = q.front(); 66 q.pop(); 67 vis[t] = 0; 68 for(int i = head[t] ; i ; i = Ed[i].upEd) 69 if(Ed[i].f && dis[Ed[i].end] < dis[t] + Ed[i].c){ 70 dis[Ed[i].end] = dis[t] + Ed[i].c; 71 flo[Ed[i].end] = min(Ed[i].f , flo[t]); 72 pre[Ed[i].end] = i; 73 if(!vis[Ed[i].end]){ 74 vis[Ed[i].end] = 1; 75 q.push(Ed[i].end); 76 } 77 } 78 } 79 return dis[T] != dis[T + 1]; 80 } 81 82 int EK(){ 83 int ans = 0; 84 while(SPFA()){ 85 int cur = T , sum = 0; 86 while(cur != S){ 87 sum += Ed[pre[cur]].c; 88 Ed[pre[cur]].f -= flo[T]; 89 Ed[pre[cur] ^ 1].f += flo[T]; 90 cur = Ed[pre[cur] ^ 1].end; 91 } 92 ans += sum * flo[T]; 93 } 94 return ans; 95 } 96 97 int lsh[MAXN] , L[MAXN][2][2] , len[MAXN] , cntL; 98 99 int main(){100 #ifndef ONLINE_JUDGE101 freopen("in" , "r" , stdin);102 //freopen("out" , "w" , stdout);103 #endif104 N = read();105 M = read();106 for(int i = 1 ; i <= N ; ++i){107 lsh[++cntL] = L[i][0][0] = read();108 L[i][0][1] = read();109 lsh[++cntL] = L[i][1][0] = read();110 L[i][1][1] = read();111 len[i] = sqrt(1ll * (L[i][1][0] - L[i][0][0]) * (L[i][1][0] - L[i][0][0]) + 1ll * (L[i][1][1] - L[i][0][1]) * (L[i][1][1] - L[i][0][1]));112 }113 sort(lsh + 1 , lsh + cntL + 1);114 cntL = unique(lsh + 1 , lsh + cntL + 1) - lsh - 1;115 T = cntL * 2 + 1;116 for(int i = 0 ; i <= cntL * 2 ; ++i){117 addEd(i , i + 1 , M);118 addEd(i + 1 , i , 0);119 }120 for(int i = 1 ; i <= N ; ++i){121 L[i][0][0] = (lower_bound(lsh + 1 , lsh + cntL + 1 , L[i][0][0]) - lsh) * 2 - 1;122 L[i][1][0] = (lower_bound(lsh + 1 , lsh + cntL + 1 , L[i][1][0]) - lsh) * 2 - 1;123 if(L[i][1][0] == L[i][0][0])124 ++L[i][1][0];125 else126 ++L[i][0][0];127 addEd(L[i][0][0] , L[i][1][0] , 1 , len[i]);128 addEd(L[i][1][0] , L[i][0][0] , 0 , -len[i]);129 }130 cout << EK();131 return 0;132 }
最长K可重线段集

转载于:https://www.cnblogs.com/Itst/p/9786016.html

你可能感兴趣的文章
python查询mangodb
查看>>
consonant combination
查看>>
驱动的本质
查看>>
Swift的高级分享 - Swift中的逻辑控制器
查看>>
Swagger简单介绍
查看>>
Python数据分析入门案例
查看>>
vue-devtools 获取到 vuex store 和 Vue 实例的?
查看>>
Linux 中【./】和【/】和【.】之间有什么区别?
查看>>
内存地址对齐
查看>>
看门狗 (监控芯片)
查看>>
css背景样式
查看>>
JavaScript介绍
查看>>
开源网络漏洞扫描软件
查看>>
yum 命令跳过特定(指定)软件包升级方法
查看>>
创新课程管理系统数据库设计心得
查看>>
Hallo wolrd!
查看>>
16下学期进度条2
查看>>
Could not resolve view with name '***' in servlet with name 'dispatcher'
查看>>
Chapter 3 Phenomenon——12
查看>>
C语言中求最大最小值的库函数
查看>>