https://www.nowcoder.com/acm/contest/206/A
POINT:
这题本质上就是一个网络流。但它的边的花费是流量的平方。
我们可以对每个点对,增加几条边,花费分别为1,3,5,7,9.容量为1.
这样就实现了花费为流量的平方。
#include <bits/stdc++.h>
using namespace std;
#define LL long long
typedef pair<int,int> pr;
const int maxn =5000;
const int inf = 0x3f3f3f3f;
struct node
{
int x,y;
};
int s,t;
struct edge
{
int from,to,cap,flow,cost;
edge(int u,int v,int c,int f,int dd):
from(u),to(v),cap(c),flow(f),cost(dd){}
};
vector<int>G[maxn];
vector<edge>len;
void add(int u,int v,int cap,int cost)
{
len.push_back(edge(u,v,cap,0,cost));
len.push_back(edge(v,u,0,0,-cost));
G[u].push_back(len.size()-2);
G[v].push_back(len.size()-1);
}
bool spfa(int &ans)
{
int dis[maxn],pre[maxn],inq[maxn];
for(int i=1;i<=t;i++) dis[i]=inf;
memset(inq,0,sizeof inq);
memset(pre,-1,sizeof pre);
dis[0]=0;
pre[0]=0;
inq[0]=1;
int a=inf;
queue<int> q;
q.push(0);
while(!q.empty())
{
int u=q.front();q.pop();inq[u]=0;
for(int i=0;i<G[u].size();i++)
{
edge e = len[G[u][i]];
if(e.cap>e.flow&&dis[e.to]>dis[u]+e.cost)
{
dis[e.to]=dis[u]+e.cost;
a=min(a,e.cap-e.flow);
pre[e.to]=G[u][i];
if(!inq[e.to])
{
q.push(e.to);
inq[e.to]=1;
}
}
}
}
if(dis[t]==inf) return 0;
ans+=dis[t];
int u=t;
while(u!=s)
{
len[pre[u]].flow+=a;
len[pre[u]^1].flow-=a;
u=len[pre[u]].from;
}
return 1;
}
int mincost()
{
int cost=0;
while(spfa(cost))
{
}
return cost;
}
//void add(int u,int v,int cap,int cost)
//25*m+j+30 区域 1-m
//2000+i 蜡烛 1-n
//t=2100;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int j=1;j<=m;j++){
for(int i=1;i<=25;i++){
int cost=2*i-1;
add(0,j*25+i,1,cost);
add(j*25+i,25*m+j+30,1,0);
}
}
for(int i=1;i<=n;i++){
int x,y;scanf("%d%d",&x,&y);
add(25*m+x+30,2000+i,1,0);
add(25*m+y+30,2000+i,1,0);
add(2000+i,2100,1,0);
}
s=0;t=2100;
printf("%d\n",mincost());
}