【洛谷 P4134】 [BJOI2012]連連看(費用流)
阿新 • • 發佈:2019-03-09
org const set pop main %d from += spa
題目鏈接
首先是可以\(O(n^2)\)枚舉出所有符合要求的點對的,然後考慮建圖。
還是拆點把每個點拆成入點和出點,源點連入點,出點連匯點,流量都是1,費用都是0。
然後對於沒對符合要求的\((x,y)\),連接\((x_{in},y_{out}),(y_{in},x_{out})\),費用均為\(x+y\),流量均為\(1\)。
然後跑出最大費用最大流,最大流除以2就是第一問,最大費用除以2就是第二問。
為什麽要雙向連邊然後答案除以2?單向連邊去試試就知道了
PS:會重復。
#include <cstdio> #include <queue> #include <cmath> #include <cstring> #define INF 2147483647 using namespace std; const int MAXN = 5010; const int MAXM = 200010; queue <int> q; int s, t, now, n, m; struct Edge{ int from, next, to, rest, cost; }e[MAXM]; int head[MAXN], num = 1, dis[MAXN], vis[MAXN], Flow[MAXN], pre[MAXN]; inline void Add(int from, int to, int flow, int cost){ e[++num] = (Edge){ from, head[from], to, flow, cost }; head[from] = num; e[++num] = (Edge){ to, head[to], from, 0, -cost }; head[to] = num; } int RoadsExist(){ q.push(s); memset(dis, 127, sizeof dis); dis[s] = 0; Flow[s] = INF; pre[t] = 0; while(!q.empty()){ now = q.front(); q.pop(); vis[now] = 0; for(int i = head[now]; i; i = e[i].next) if(e[i].rest && dis[e[i].to] > dis[now] + e[i].cost){ dis[e[i].to] = dis[now] + e[i].cost; pre[e[i].to] = i; Flow[e[i].to] = min(Flow[now], e[i].rest); if(!vis[e[i].to]){ vis[e[i].to] = 1; q.push(e[i].to); } } } return pre[t]; } int a, b, c, d, maxflow, mincost; int gcd(int a, int b){ return b ? gcd(b, a % b) : a; } int main(){ scanf("%d%d", &a, &b); s = 4999; t = 5000; for(int i = a; i <= b; ++i){ Add(s, i, 1, 0); Add(i + 1000, t, 1, 0); for(int j = a; j < i; ++j){ c = i * i - j * j; d = sqrt(c); if(d * d == c && gcd(d, j) == 1){ Add(i, j + 1000, 1, -i - j); Add(j, i + 1000, 1, -i - j); } } } while(RoadsExist()){ maxflow += Flow[t]; mincost += Flow[t] * dis[t]; for(int i = t; i != s; i = e[pre[i]].from){ e[pre[i]].rest -= Flow[t]; e[pre[i] ^ 1].rest += Flow[t]; } } printf("%d %d\n", maxflow >> 1, -mincost >> 1); return 0; }
【洛谷 P4134】 [BJOI2012]連連看(費用流)