题目链接:https://www.luogu.org/problem/P4014
沙雕题,建图很简单。
跑一遍最小费用,再把边权取反重跑一遍最小费用。
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 250;
int n,m,S,T,tot;
int head[N];
struct node{
int v,cap,cost,nxt;
}edge[int(2e5+100)];
int dis[N],pre[N],last[N],flow[N],maxflow,mincost; //pre:前驱结点 last:每个点所连的前一条边 flow:源点到该点的流量
bool vis[N];
void ae(int u,int v,int cap,int cost){ //前向星加边
edge[++tot] = node{v,cap,cost,head[u]};
head[u] = tot;
}
bool spfa() {
memset(dis,0x7f,sizeof(dis));
memset(flow,0x7f,sizeof(flow)); //2e9
memset(vis,0,sizeof(vis));
deque<int> q;
q.push_back(S);
vis[S] = 1; dis[S] = 0; pre[T] = -1;
while(!q.empty()) {
int u = q.front();
q.pop_front();
vis[u] = 0;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(edge[i].cap>0&&dis[v]>dis[u]+edge[i].cost) {
dis[v] = dis[u]+edge[i].cost;
pre[v] = u;
last[v] = i;
flow[v] = min(flow[u],edge[i].cap);
if(!vis[v]) {
vis[v] = 1;
if(dis[v]<=dis[u]) q.push_front(v);
else q.push_back(v);
}
}
}
}
return pre[T] != -1;
}
void dinic(){
while(spfa()){
int now = T;
maxflow += flow[T];
mincost += flow[T]*dis[T];
while(now!=S) {
edge[last[now]].cap -= flow[T];
edge[last[now]^1].cap += flow[T];
now = pre[now];
}
}
return ;
}
void init() {
tot = -1;
maxflow = 0;
mincost = 0;
memset(head,-1,sizeof(head));
}
int s[110][110];
int main() {
freopen("a.txt","r",stdin);
// ios::sync_with_stdio(0);
scanf("%d",&n);
init();
S = 0;
T = 2*n+1;
rep(i, 1, n)
rep(j, 1, n) {
scanf("%d",&s[i][j]);
ae(i,j+n,1,s[i][j]);
ae(j+n,i,0,-s[i][j]);
}
rep(i, 1, n) {
ae(S,i,1,0);
ae(i,S,0,0);
ae(i+n,T,1,0);
ae(T,i+n,0,0);
}
dinic();
printf("%d\n",mincost);
init();
S = 0;
T = 2*n+1;
rep(i, 1, n)
rep(j, 1, n) {
s[i][j] = -s[i][j];
ae(i,j+n,1,s[i][j]);
ae(j+n,i,0,-s[i][j]);
}
rep(i, 1, n) {
ae(S,i,1,0);
ae(i,S,0,0);
ae(i+n,T,1,0);
ae(T,i+n,0,0);
}
dinic();
printf("%d\n",-mincost);
return 0;
}