dicnic模板
struct Dicnic {
#define Type int
int n, m, s, t; //节点数,边数(包括反向弧),源点编号和汇点编号
vector<Edge> edges; //边表。edge[e]和edge[e^1]互为反向弧
vector<int> G[N]; //邻接表,G[i][j]表示节点i的第j条边在e数组中的编号
bool vis[N]; //BFS使用
Type d[N]; //从起点到i的距离
int cur[N]; //当前弧下标
void init(int n) {
this->n = n;
for (int i = 0; i <= n; ++i) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap) {
edges.emplace_back(Edge(from, to, cap, 0));
edges.emplace_back(Edge(to, from, 0, 0));
m = int(edges.size());
G[from].emplace_back(m-2);
G[to].emplace_back(m-1);
}
bool BFS() {
memset(vis, 0, sizeof(vis));
memset(d, 0, sizeof(d));
queue<int> q;
while (!q.empty()) q.pop();
q.push(s);
d[s] = 0;
vis[s] = 1;
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = 0; i < int(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];
}
Type DFS(int x, Type a) {
if (x == t || a == 0) return a;
Type flow = 0, f;
for (int &i = cur[x]; i < int(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;
}
Type Maxflow(int s, int t) {
this->s = s; this->t = t;
Type flow = 0;
while (BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
#undef Type
}dicnic;
spfa费用流模板
struct MCMF {
int n, m;
vector<Edge> edges;
vector<int> G[N];
int inq[N]; //是否在队列中
int d[N]; //bellmanford
int p[N]; //上一条弧
int a[N]; //可改进量
void init(int n) {
this->n = n;
for (int i = 0; i <= n; ++i) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap, int cost) {
edges.emplace_back(Edge(from, to, cap, 0, cost));
edges.emplace_back(Edge(to, from, 0, 0, -cost));
m = int(edges.size());
G[from].emplace_back(m - 2);
G[to].emplace_back(m - 1);
}
bool spfa(int s, int t, int &flow, ll &cost) {
for (int i = 1; i <= n; ++i) d[i] = INF;
memset(inq, 0, sizeof(inq));
d[s] = 0;
inq[s] = 1;
p[s] = 0;
a[s] = INF;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for (int i = 0; i < int(G[u].size()); ++i) {
Edge &e = edges[G[u][i]];
if (e.cap > e.flow && d[e.to] > d[u] + e.cost) {
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if (!inq[e.to]) {
q.push(e.to);
inq[e.to] = 1;
}
}
}
}
//if (d[t] > k) return false; //如果费用大于k就退出
//if (d[t] >= 0) return false; //最小费用流
if (d[t] == INF) return false;
flow += a[t];
cost += (ll)d[t] * (ll)a[t];
for (int u = t; u != s; u = edges[p[u]].from) {
edges[p[u]].flow += a[t];
edges[p[u] ^ 1].flow -= a[t];
}
return true;
}
int MincostMaxflow(int s, int t, ll &cost) {
int flow = 0;
cost = 0;
while (spfa(s, t, flow, cost));
return flow;
}
}mcmf;
飞行员配对方案问题
- 飞行员配对方案问题
问题模型: 二分图最大匹配
转换模型: 最大流
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1100; //点数
int n,m,u[maxn],v[maxn];
vector<int> idx;
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
struct Edge{
int from, to, cap, flow; //如果要开ll的话,这边也要开ll
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
cin>>n>>m;
m=m-n;
dicnic.init(n+m+10);
for(int i=1; i<=n; ++i) dicnic.addEdge(0, i, 1);
for(int i=n+1; i<=n+m; ++i) dicnic.addEdge(i, n+m+1, 1);
int tot=0;
while(true){
cin>>u[tot]>>v[tot];
if(u[tot]==-1 && v[tot]==-1) break;
dicnic.addEdge(u[tot], v[tot], 1);
idx.emplace_back(dicnic.m-2);
tot++;
}
cout<<dicnic.Maxflow(0, n+m+1)<<'\n';
for(int x:idx){
if(dicnic.edges[x].flow==dicnic.edges[x].cap){
cout<<dicnic.edges[x].from<<' '<<dicnic.edges[x].to<<'\n';
}
}
return 0;
}
太空飞行计划问题
- 太空飞行计划问题
问题模型: 最大权闭合子图
转换模型: 最小割
最大权闭合子图是一个权值和最大的子图,这个子图中每个点的后继也都在子图里
。而这正是这题所限定的,某个实验一定需要规定的器材。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1100; //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,m,x;
struct Edge{
int from, to, cap, flow; //如果要开ll的话,这边也要开ll
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
scanf("%d%d", &m, &n);
int S=0, T=m+n+1;
dicnic.init(T+5);
int sum=0;
for(int i=1; i<=m; ++i){
int x;
scanf("%d", &x);
sum+=x;
dicnic.addEdge(S, i, x);
while(getchar()==' '){
scanf("%d", &x);
dicnic.addEdge(i, x+m, INF);
}
}
for(int i=1; i<=n; ++i){
int x;
scanf("%d", &x);
dicnic.addEdge(i+m, T, x);
}
int mincut=dicnic.Maxflow(S, T);
for(int i=1; i<=m; ++i) if(dicnic.d[i]) printf("%d ", i);
puts("");
for(int i=m+1; i<=m+n; ++i) if(dicnic.d[i]) printf("%d ", i-m);
puts("");
printf("%d\n", sum-mincut);
return 0;
}
最小路径覆盖问题
- 最小路径覆盖问题
问题模型: 有向无环图最小路径覆盖
转换模型: 点数 - 最大流
最后输出路径挺有意思的,首先明确中间的流只要满流,就说明他们连接的两个点连线是最小路径覆盖里的一条路,先用并查集维护一下起点,然后对于每个起点O(n^2)
输出路径。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1100; //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,m,fa[maxn];
struct Edge{
int from, to, cap, flow; //如果要开ll的话,这边也要开ll
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int findRoot(int x){
if(x==fa[x]) return x;
else{
fa[x]=findRoot(fa[x]);
return fa[x];
}
}
void uniRoot(int a, int b){
int aa=findRoot(a);
int bb=findRoot(b);
if(aa!=bb){
fa[bb]=aa;
}
}
void output(int x){
int now=x;
while(true){
cout<<now<<' ';
bool flag=false;
for(int idx:dicnic.G[now]){
Edge temp=dicnic.edges[idx];
if(temp.from>=1 && temp.from<=n && temp.to>=n+1 && temp.to<=2*n && temp.flow==temp.cap){
flag=true;
now=temp.to-n;
break;
}
}
if(!flag) {
cout<<'\n';
break;
}
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
cin>>n>>m;
dicnic.init(2*n+10);
int s=0,t=2*n+1;
vector<int> temp;
for(int i=0; i<m; ++i){
int u,v;
cin>>u>>v;
dicnic.addEdge(u, v+n, 1);
temp.emplace_back(dicnic.m-2);
}
for(int i=1; i<=n; ++i) dicnic.addEdge(s, i, 1);
for(int i=n+1; i<=2*n; ++i) dicnic.addEdge(i, t, 1);
int maxflow=dicnic.Maxflow(s,t);
int ans=n-maxflow;
for(int i=0; i<=1000; ++i) fa[i]=i;
for(int x:temp){
Edge now=dicnic.edges[x];
if(now.flow==now.cap){
uniRoot(now.from, now.to-n);
}
}
for(int i=1; i<=n; ++i){
if(findRoot(i)==i){
output(i);
}
}
cout<<ans<<'\n';
return 0;
}
圆桌问题
- 圆桌问题
问题模型: 二分图多重匹配
转换模型: 最大流
#include <bits/stdc++.h>
using namespace std;
const int N = 1000+100; //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,m,r[N],c[N];
vector<int> ans[N];
vector< pair<int, int> > idx[N];
struct Edge{
int from, to, cap, flow; //如果要开ll的话,这边也要开ll
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n>>m;
dicnic.init(n+m+10);
int S=0, T=n+m+1;
int sum=0;
for(int i=1; i<=n; ++i){
cin>>r[i];
sum+=r[i];
dicnic.addEdge(S, i, r[i]);
}
for(int i=n+1; i<=n+m; ++i){
cin>>c[i];
dicnic.addEdge(i, T, c[i]);
}
for(int i=1; i<=n; ++i){
for(int j=n+1; j<=n+m; ++j){
dicnic.addEdge(i, j, 1);
idx[i].emplace_back(make_pair(dicnic.m-2, j-n));
}
}
int maxflow=dicnic.Maxflow(S, T);
if(maxflow!=sum) cout<<0<<'\n';
else{
cout<<1<<'\n';
for(int i=1; i<=n; ++i){
for(pair<int, int> pii:idx[i]){
Edge temp=dicnic.edges[pii.first];
if(temp.flow==temp.cap){
ans[i].emplace_back(pii.second);
}
}
}
for(int i=1; i<=n; ++i){
for(int x:ans[i]) cout<<x<<' ';
cout<<'\n';
}
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
最长不下降子序列问题
问题模型: 最多不相交路径
转换模型: 最大流
第一次做到要特判
n=1
情况的网络流题啊,233。
#include <bits/stdc++.h>
using namespace std;
const int N = 2100; //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,a[N],dp[N];
struct Edge{
int from, to, cap, flow; //如果要开ll的话,这边也要开ll
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n;
if(n==1){
cout<<1<<'\n';
cout<<1<<'\n';
cout<<1<<'\n';
return 0;
}
for(int i=1; i<=n; ++i){
cin>>a[i];
dp[i]=1;
}
int maxx=1;
for(int i=1; i<=n; ++i){
for(int j=1; j<i; ++j){
if(a[j]<=a[i]) dp[i]=max(dp[i], dp[j]+1);
}
maxx=max(maxx, dp[i]);
}
cout<<maxx<<'\n';
dicnic.init(2*n+20);
int s=0, t=2*n+1;
for(int i=1; i<=n; ++i){
if(dp[i]==1) dicnic.addEdge(s, i, 1);
if(dp[i]==maxx) dicnic.addEdge(i+n, t, 1);
dicnic.addEdge(i, i+n, 1);
for(int j=1; j<i; ++j){
if(a[j]<=a[i] && dp[i]==dp[j]+1){
dicnic.addEdge(j+n, i, 1);
}
}
}
int maxflow=dicnic.Maxflow(s, t);
cout<<maxflow<<'\n';
dicnic.init(2*n+20);
for(int i=1; i<=n; ++i){
if(dp[i]==1){
if(i==1) dicnic.addEdge(s, i, INF);
else dicnic.addEdge(s, i, 1);
}
if(dp[i]==maxx) {
if(i==n) dicnic.addEdge(i+n, t, INF);
else dicnic.addEdge(i+n, t, 1);
}
if(i==1 || i==n) dicnic.addEdge(i, i+n, INF);
else dicnic.addEdge(i, i+n, 1);
for(int j=1; j<i; ++j){
if(a[j]<=a[i] && dp[i]==dp[j]+1){
dicnic.addEdge(j+n, i, 1);
}
}
}
maxflow=dicnic.Maxflow(s, t);
cout<<maxflow<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
试题库问题
问题模型: 二分图多重匹配
转化模型: 最大流
#include <bits/stdc++.h>
using namespace std;
const int N = 1300; //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,k,need[N];
vector<int> ans[N];
vector<int> rev;
struct Edge{
int from, to, cap, flow; //如果要开ll的话,这边也要开ll
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n>>k;
int sum=0;
int s=0, t=n+k+1;
for(int i=1; i<=n; ++i){
cin>>need[i];
dicnic.addEdge(k+i, t, need[i]);
sum+=need[i];
}
for(int i=1; i<=k; ++i){
int num;
cin>>num;
for(int j=0; j<num; ++j){
int x;
cin>>x;
dicnic.addEdge(i, k+x, 1);
rev.emplace_back(dicnic.m-2); //还是先把最后要处理的边存起来好一点,防止出错
}
}
for(int i=1; i<=k; ++i) dicnic.addEdge(s, i, 1);
int maxflow=dicnic.Maxflow(s, t);
for(int idx:rev){
Edge now=dicnic.edges[idx];
if(now.cap==now.flow){
ans[now.to-k].emplace_back(now.from);
}
}
if(maxflow!=sum) cout<<"No Solution!"<<'\n';
for(int i=1; i<=n; ++i){
cout<<i<<": ";
for(int x:ans[i]) cout<<x<<' ';
cout<<'\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
方格取数问题
问题模型: 二分图最大点权独立集
转化模型: 最小割
#include <bits/stdc++.h>
using namespace std;
const int MA=110;
const int N = 10100; //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int mat[MA][MA],idx[MA][MA],n,m,dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
struct Edge{
int from, to, cap, flow; //如果要开ll的话,这边也要开ll
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n>>m;
int tot=0;
int sum=0;
for(int i=1; i<=n; ++i){
for(int j=1; j<=m; ++j){
cin>>mat[i][j];
sum+=mat[i][j];
idx[i][j]=++tot;
}
}
int s=0, t=tot+1;
for(int i=1; i<=n; ++i){
for(int j=1; j<=m; ++j){
if((i+j)%2==0) {
dicnic.addEdge(s, idx[i][j], mat[i][j]);
for(int k=0; k<4; ++k){
int ti=i+dir[k][0];
int tj=j+dir[k][1];
if(ti<1 || ti>n || tj<1 || tj>m) continue;
dicnic.addEdge(idx[i][j], idx[ti][tj], INF);
}
}
else dicnic.addEdge(idx[i][j], t, mat[i][j]);
}
}
cout<<(sum-dicnic.Maxflow(s, t))<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
负载平衡问题
题目模型: 最小代价供求
转化模型: 最小费用最大流
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 200; //点数
const int INF = 0x3f3f3f3f;
int n,a[N];
struct Edge{
int from, to, cap, flow, cost;
Edge(int u, int v, int c, int f, int cc)
: from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
}mcmf;
int myabs(int x){
if(x<0) x=-x;
return x;
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n;
int sum=0;
for(int i=1; i<=n; ++i){
cin>>a[i];
sum+=a[i];
}
int s=0, t=n+1;
int avg=sum/n;
mcmf.init(n+5);
for(int i=1; i<=n; ++i){
if(a[i]>avg) mcmf.addEdge(s,i,a[i]-avg,0);
else if(a[i]<avg) mcmf.addEdge(i,t,avg-a[i],0);
}
for(int i=1; i<=n; ++i){
if(a[i]>avg){
for(int j=1; j<=n; ++j){
if(a[j]<avg){
int temp=min(myabs(j-i), n-myabs(j-i));
mcmf.addEdge(i, j, INF, temp);
}
}
}
}
ll cost=0;
ll maxflow=mcmf.MincostMaxflow(s,t,cost);
cout<<cost<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
运输问题
问题模型: 网络费用流量
转化模型: 最小费用最大流
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 510; //点数
const int INF = 0x3f3f3f3f;
int n,m,a[N],b[N],mat[N][N];
struct Edge{
int from, to, cap, flow, cost;
Edge(int u, int v, int c, int f, int cc)
: from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
}mcmf;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>m>>n;
int s=0, t=n+m+1;
mcmf.init(t+5);
for(int i=1; i<=m; ++i){
cin>>a[i];
mcmf.addEdge(s,i,a[i],0);
}
for(int i=1; i<=n; ++i){
cin>>b[i];
mcmf.addEdge(i+m,t,b[i],0);
}
for(int i=1; i<=m; ++i){
for(int j=1; j<=n; ++j){
cin>>mat[i][j];
mcmf.addEdge(i,m+j,INF,mat[i][j]);
}
}
ll co=0;
ll maxflow=mcmf.MincostMaxflow(s,t,co);
cout<<co<<'\n';
mcmf.init(t+5);
for(int i=1; i<=m; ++i) mcmf.addEdge(s,i,a[i],0);
for(int i=1; i<=n; ++i) mcmf.addEdge(i+m,t,b[i],0);
for(int i=1; i<=m; ++i){
for(int j=1; j<=n; ++j){
mcmf.addEdge(i,m+j,INF,-mat[i][j]);
}
}
co=0;
maxflow=mcmf.MincostMaxflow(s,t,co);
cout<<-co<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
骑士共存问题
问题模型: 二分图最大独立集
转化模型: 最小割
#include <bits/stdc++.h>
using namespace std;
const int N = 40000+100; //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,m,mat[210][210],dir[8][2]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}};
struct Edge{
int from, to, cap, flow; //如果要开ll的话,这边也要开ll
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
memset(mat,0,sizeof(mat));
cin>>n>>m;
for(int i=0; i<m; ++i){
int a,b;
cin>>a>>b;
mat[a][b]=-1;
}
int tot=1;
int cnt=0;
for(int i=1; i<=n; ++i){
for(int j=1; j<=n; ++j){
if(mat[i][j]==-1) continue;
mat[i][j]=tot++;
++cnt;
}
}
int s=0, t=tot;
dicnic.init(tot+10);
for(int i=1; i<=n; ++i){
for(int j=1; j<=n; ++j){
if(mat[i][j]==-1) continue;
if((i+j)%2==0){
dicnic.addEdge(s,mat[i][j],1);
for(int k=0; k<8; ++k){
int tx=i+dir[k][0];
int ty=j+dir[k][1];
if(tx<1 || tx>n || ty<1 || ty>n || mat[tx][ty]==-1) continue;
dicnic.addEdge(mat[i][j],mat[tx][ty],1);
}
} else{
dicnic.addEdge(mat[i][j],t,INF);
}
}
}
int maxflow=dicnic.Maxflow(s,t);
cout<<cnt-maxflow<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
航空路线问题
题目模型: 最长不相交路径
思路: 最大费用最大流 == 负费用边最小费用最大流
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1100; //点数
const int INF = 0x3f3f3f3f;
int n,m,tot=0,vis[N];
string s[N];
map<string,int> idx;
vector<int> v1,v2;
struct Edge{
int from, to, cap, flow, cost;
Edge(int u, int v, int c, int f, int cc)
: from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
}mcmf;
void dfs1(int now){
for(int x:mcmf.G[now+n]){
Edge e=mcmf.edges[x];
if(e.to<=n && e.cap==e.flow && !vis[e.to]){
vis[e.to]=1;
v1.emplace_back(e.to);
dfs1(e.to);
break; //一定要立刻break,想想为什么
}
}
}
void dfs2(int now){
for(int x:mcmf.G[now+n]){
Edge e=mcmf.edges[x];
if(e.to<=n && e.cap==e.flow && !vis[e.to]){
vis[e.to]=1;
v2.emplace_back(e.to);
dfs2(e.to);
break;
}
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n>>m;
mcmf.init(2*n+10);
for(int i=1; i<=n; ++i){
cin>>s[i];
idx[s[i]]=++tot;
}
int S=1,T=2*n;
for(int i=1; i<=n; ++i){
if(i==1 || i==n) mcmf.addEdge(i,i+n,2,-1);
else mcmf.addEdge(i,i+n,1,-1);
}
bool sp=false;
for(int i=0; i<m; ++i){
string s1,s2;
cin>>s1>>s2;
if(idx[s1]>idx[s2]){
swap(s1,s2);
}
if(idx[s1]==1 && idx[s2]==n) sp=true;
mcmf.addEdge(idx[s1]+n,idx[s2],1,0);
}
ll co=0;
ll maxflow=mcmf.MincostMaxflow(S,T,co);
if(maxflow==2){
cout<<-co-2<<'\n';
memset(vis,0,sizeof(vis));
dfs1(1);
dfs2(1);
reverse(v2.begin(),v2.end());
cout<<s[1]<<'\n';
for(int x:v1){
cout<<s[x]<<'\n';
}
for(int x:v2){
cout<<s[x]<<'\n';
}
cout<<s[1]<<'\n';
} else if(maxflow==1 && sp){
cout<<2<<'\n';
cout<<s[1]<<'\n';
cout<<s[n]<<'\n';
cout<<s[1]<<'\n';
}
else{
cout<<"No Solution!"<<'\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
餐巾纸计划问题
问题模型: 线性规划网络流优化(我也不知道这是个啥,别人这么总结的。。)
转化模型: 最小费用最大流
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5000+100; //点数
const int INF = 0x3f3f3f3f;
int num,a[N],p,m,f,n,s;
struct Edge{
int from, to, cap, flow, cost;
Edge(int u, int v, int c, int f, int cc)
: from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
}mcmf;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
//1~num坏抹布
//num+1~2*num好抹布
cin>>num;
mcmf.init(2*num+10);
for(int i=1; i<=num; ++i) cin>>a[i];
int S=0,T=2*num+1;
cin>>p>>m>>f>>n>>s;
for(int i=1; i<=num; ++i){
mcmf.addEdge(S,i,a[i],0);
mcmf.addEdge(i+num,T,a[i],0);
mcmf.addEdge(S,i+num,INF,p);
if(i+1<=num) mcmf.addEdge(i,i+1,INF,0);
if(i+m<=num) mcmf.addEdge(i,i+m+num,INF,f);
if(i+n<=num) mcmf.addEdge(i,i+n+num,INF,s);
}
ll co=0;
int maxflow=mcmf.MincostMaxflow(S,T,co);
cout<<co<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
最长k可重区间问题
问题模型: 不相交路径最大权
转化模型: 最大费用最大流
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1100; //点数
const int INF = 0x3f3f3f3f;
int n,k;
vector<int> b;
struct node{
int l,r,len;
}nd[N];
struct Edge{
}mcmf;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n>>k;
mcmf.init(2*n+10);
for(int i=0; i<n; ++i){
cin>>nd[i].l>>nd[i].r;
nd[i].len=nd[i].r-nd[i].l;
b.emplace_back(nd[i].l);
b.emplace_back(nd[i].r);
}
sort(b.begin(),b.end());
b.resize(unique(b.begin(),b.end())-b.begin());
int len=int(b.size());
int S=0,T=len+1;
mcmf.addEdge(S,1,k,0);
mcmf.addEdge(len,T,INF,0);
for(int i=1; i<=len-1; ++i) mcmf.addEdge(i,i+1,INF,0);
for(int i=0; i<n; ++i){
int tl=lower_bound(b.begin(),b.end(),nd[i].l)-b.begin()+1;
int tr=lower_bound(b.begin(),b.end(),nd[i].r)-b.begin()+1;
mcmf.addEdge(tl,tr,1,-nd[i].len);
}
ll co=0;
int maxflow=mcmf.MincostMaxflow(S,T,co);
cout<<-co<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
魔术球问题
问题模型: 有向无环图最小路径覆盖
转化模型: 最大流
const int N = 10100; //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,vis[N];
struct Edge{
int from, to, cap, flow; //如果要开ll的话,这边也要开ll
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
signed main() {
cin>>n;
dicnic.init(1000);
int sum=0,now=1; //now是柱子
int S=0,T=10010;
for(;;){
dicnic.addEdge(S,now*2,1);
dicnic.addEdge(now*2+1,T,1);
for(int i=int(sqrt(now))+1; i*i<now*2; ++i) dicnic.addEdge((i*i-now)*2,now*2+1,1);
int add=dicnic.Maxflow(S,T);
sum+=add;
if(now-sum>n){
break;
}
++now;
}
--now;
cout<<now<<'\n';
ms(vis,0);
for(int i=1; i<=now; ++i){
if(vis[i]) continue;
vis[i]=1;
cout<<i<<' ';
int u=i;
for(;;){
bool exec=false;
for(int idx:dicnic.G[u*2]){
Edge e=dicnic.edges[idx];
if(e.flow==e.cap && e.to!=0){ //注意不能是流向源点的边!
exec=true;
u=(e.to-1)/2;
vis[u]=1;
cout<<u<<' ';
break;
}
}
if(!exec) break;
}
cout<<'\n';
}
return 0;
}