Birthday
题解:本题…关键就在于建图。
首先,从源点向每一根蜡烛建一条费用为 0 0 0流量为 1 1 1的边。其次,考虑将每个 p a r t part part拆成 n n n个点,代表 n n n个时间差,选择第 i i i个点的时候,就代表第插第 i i i根蜡烛与第 i − 1 i-1 i−1根蜡烛的时间差,因此就是 1 , 3 , 5 , 7 , 9... 1,3,5,7,9... 1,3,5,7,9...即 i 2 − ( i − 1 ) 2 i^2-(i-1)^2 i2−(i−1)2。拆分的共 m ⋅ n m\cdot n m⋅n个点朝汇点连费用为 0 0 0流量为 1 1 1的边。中间的话,从每一根蜡烛向所能插的区域各建一条边,连向第 i i i个点的费用为 i 2 − ( i − 1 ) 2 i^2-(i-1)^2 i2−(i−1)2。
建完图然后跑最小费用最大流即可。
代码
#include<bits/stdc++.h>
const int MAXN = 1111, MAXM = 11111, inf = 1e9;
using namespace std;
struct Edge{
int to, next, cap, flow, cost;
}e[MAXM];
int head[MAXN] ,tol,N;
int pre[MAXN], dis[MAXN];
bool vis[MAXN];
void init(int n){
N = n;
tol = 0;
memset(head,-1,sizeof head);
}
void addedge(int u,int v,int cap,int cost){
e[tol].to = v;
e[tol].cap = cap;
e[tol].cost = cost;
e[tol].flow = 0;
e[tol].next = head[u];
head[u] = tol++;
e[tol].to = u;
e[tol].cap = 0;
e[tol].cost = -cost;
e[tol].flow = 0;
e[tol].next = head[v];
head[v] = tol++;
}
bool spfa(int s,int t){
queue<int> q;
memset(pre,-1,sizeof pre);
memset(vis,0,sizeof vis);
for(int i = s; i <= t; ++i){
dis[i] = inf;
}
dis[s] = 0;
vis[s] = 1;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].to;
if(e[i].cap > e[i].flow && dis[v] > dis[u] + e[i].cost){
dis[v] = dis[u] + e[i].cost;
pre[v] = i;
if(!vis[v]){
vis[v] = 1;
q.push(v);
}
}
}
}
if(pre[t] == -1) return 0;
else return 1;
}
int minCostMaxFlow(int s,int t,int &cost){
int flow = 0;
cost = 0;
while(spfa(s,t)){
int Min = inf;
for(int i = pre[t]; i != -1; i = pre[e[i^1].to]){
if(Min > e[i].cap - e[i].flow)
Min = e[i].cap - e[i].flow;
}
for(int i = pre[t]; i != -1; i = pre[e[i^1].to]){
e[i].flow += Min;
e[i ^ 1].flow -= Min;
cost += e[i].cost * Min;
}
flow += Min;
}
return flow;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int n,m,x,y,cost;
cin>>n>>m;
init(n+m+1);
for(int i = 1; i <= n; ++i){
cin>>x>>y;
addedge(0,i,1,0);
addedge(i,x+n,1,0);
addedge(i,y+n,1,0);
}
for(int i = 1; i <= m; ++i){
for(int j = 1; j <= 2 * n; j += 2){
addedge(i+n,m+n+1,1,j);
}
}
minCostMaxFlow(0,n+m+1,cost);
cout<<cost<<endl;
return 0;
}