题目及链接地址
TOJ4085: Drainage Ditcheshttp://210.32.82.1/acmhome/showstatus.do?&page=1&problemId=4085
TOJ1625: Secret Milking Machinehttp://210.32.82.1/acmhome/showstatus.do?&page=1&problemId=1625
TOJ3385: Anti LIShttp://210.32.82.1/acmhome/problemdetail.do?&method=showdetail&id=3385
HDU2164Smallest Minimum Cuthttp://acm.hdu.edu.cn/showproblem.php?pid=6214
HDU6118度度熊的交易计划http://acm.hdu.edu.cn/showproblem.php?pid=6118
2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 J. Our Journey of Dalian Ends https://nanti.jisuanke.com/t/16959
网络流天下第一
4085: Drainage Ditches 
Total Submit: 120 Accepted:82
Description
Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie's clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.
Input
The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.
Output
For each case, output a single integer, the maximum rate at which water may emptied from the pond.
Sample Input
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
Sample Output
50
n个点,m条边,给一个有向图,源点1,汇点n,求一个最大流
红书模板,应该是Dinic
#include<stdio.h> #include<algorithm> using namespace std; const int INF=1<<30; const int N=505; int n,m,ans,x,y,z,M; int d[N],l[N],fi[N],nxt[N],to[N],w[N]; void add(int x,int y,int z) { to[++M]=y;w[M]=z;nxt[M]=fi[x];fi[x]=M; } int dfs(int now,int f) { if(now==n)return f; int used=0; for(int i=fi[now];i;i=nxt[i]) if(d[to[i]]==d[now]+1&&w[i]) { int f1=dfs(to[i],min(f-used,w[i])); w[i]-=f1,w[i^1]+=f1; used+=f1; } return used; } bool bfs() { int h=0,t=1; l[1]=1,d[1]=0; for(int i=2;i<=n;i++)d[i]=-1; while(h<t) { for(int i=fi[l[++h]];i;i=nxt[i]) if(d[to[i]]==-1&&w[i]) l[++t]=to[i],d[l[t]]=d[l[h]]+1; } return d[n]+1; } int main() { while(~scanf("%d%d",&m,&n)) { for(int i=1;i<=n;i++)fi[i]=0; for(ans=0,M=1;m;m--) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,0); while(bfs())ans+=dfs(1,INF); printf("%d ",ans); } return 0; }
1625: Secret Milking Machine 
Total Submit: 24 Accepted:9
Description
Farmer John is constructing a new milking machine and wishes to keep it secret as long as possible. He has hidden in it deep within his farm and needs to be able to get to the machine without being detected. He must make a total of T (1 <= T <= 200) trips to the machine during its construction. He has a secret tunnel that he uses only for the return trips.
The farm comprises N (2 <= N <= 200) landmarks (numbered 1..N) connected by P (1 <= P <= 40,000) bidirectional trails (numbered 1..P) and with a positive length that does not exceed 1,000,000. Multiple trails might join a pair of landmarks.
To minimize his chances of detection, FJ knows he cannot use any trail on the farm more than once and that he should try to use the shortest trails.
Help FJ get from the barn (landmark 1) to the secret milking machine (landmark N) a total of T times. Find the minimum possible length of the longest single trail that he will have to use, subject to the constraint that he use no trail more than once. (Note well: The goal is to minimize the length of the longest trail, not the sum of the trail lengths.)
It is guaranteed that FJ can make all T trips without reusing a trail.
Input
* Line 1: Three space-separated integers: N, P, and T
* Lines 2..P+1: Line i+1 contains three space-separated integers, A_i, B_i, and L_i, indicating that a trail connects landmark A_i to landmark B_i with length L_i.
Output
* Line 1: A single integer that is the minimum possible length of the longest segment of Farmer John's route.
Sample Input
7 9 2
1 2 2
2 3 5
3 7 5
1 4 1
4 3 1
4 5 7
5 7 1
1 6 3
6 7 3
Sample Output
5
Hint
Huge input data,scanf is recommended.
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int N=205,INF=1e8; int c[N][N],n,p,T; struct edge { int u,v,w; friend bool operator <(const edge &a,const edge &b) { return a.w<b.w; } } e[N*N]; void build(int mid) { memset(c,0,sizeof c); for(int i=0; i<=mid; i++) { int u=e[i].u,v=e[i].v; c[u][v]++,c[v][u]++; } } int pre[N],cur[N],level[N],gap[N]; int s,t; int SAP() { memset(cur,0,sizeof(cur)); memset(level,0,sizeof(level)); memset(gap,0,sizeof(gap)); int u=pre[s]=s,v,aug=INF,flow=0; gap[s]=n; while(level[s]<n) { for(v=cur[u]; v<=n; v++) if(c[u][v]&&level[u]==level[v]+1)break; if(v<=n) { pre[v]=u; aug=min(aug,c[u][v]); u=cur[u]=v; if(u==t) { flow+=aug; for(v=t; v!=s; v=pre[v]) { c[pre[v]][v]-=aug; c[v][pre[v]]+=aug; } aug=INF,u=s; } } else { if(!--gap[level[u]])return flow; int minlevel=n; for(v=1; v<=n; v++) if(c[u][v]&&minlevel>level[v]) cur[u]=v,minlevel=level[v]; level[u]=minlevel+1; gap[level[u]]++; u=pre[u]; } } return flow; } void la() { sort(e,e+p); s=1,t=n; int l=0,r=p-1; while(l<=r) { int mid=l+r>>1; build(mid); if(SAP()>=T) r=mid-1; else l=mid+1; } printf("%d ",e[r+1].w); } int main() { while(~scanf("%d%d%d",&n,&p,&T)) { for(int i=0; i<p; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); e[i].u=u,e[i].v=v,e[i].w=w; } la(); } return 0; }
3385: Anti LIS 
Total Submit: 2 Accepted:1
Description
Haven't you heard about Lost?
Having written a article named <Summaries of ALL Algorithms>, Lost is good at solved by algorithm problems(?). One day, GXX asked Lost to work out the Longest Increasing Subsequence(for short, LIS) of a given sequence {A_1, A_2, ..., A_N}. Knowing this problem well, Lost simply copied a program from his article and solved the problem in seconds. So that GXX became frustrated. She wanted to cheat Lost by removing some elements from the original sequence to make Lost's answer go wrong. For convinience, she would like to remove least number of elements.
Input
The beginning of the input is an integer T(T <= 10), which is the number of test cases. T cases are followed. The first line of each test case is an integer N (1 <= N <= 1,000), which denotes the length of the sequence. The second line is N integer A_1, A_2, ..., A_N, which denote the given sequence.
Output
For each test case, print a line contains a single integer which is the minimum number of the removed elements.
Sample Input
1
6
10 10 20 1 2 2
Sample Output
2
给定序列 删除最少的数使得LIS长度变短
将每个数看做一个点 首先考虑拆点 每个点转化为 一个入点 和 一个出点
入点 有一条权值为1的边指向 出点
那最少删除多少个点 就转化为最少删除多少条边
Dinic
#include<stdio.h> #include<string.h> #include<queue> #include<algorithm> using namespace std; const int INF=0x3f3f3f3f; const int N=5005; const int C=1005; const int M=1000005; struct edge { int flow,cap,v; }e[M]; int b[N],ma,s,t,ans,n; int fst[N],nxt[M],dis[N],tot,cur[N],dp[N]; queue<int>q; void pre() { ma=0; for(int i=1;i<=n;i++) { dp[i]=1; for(int j=1;j<i;j++) if(b[j]<b[i]) dp[i]=max(dp[i],dp[j]+1); ma=max(ma,dp[i]); } } void add(int x,int y,int c) { e[tot].v=y,e[tot].cap=c,e[tot].flow=0; nxt[tot]=fst[x],fst[x]=tot++; } void build(int x,int y,int c) { add(x,y,c),add(y,x,0); } bool bfs() { memset(dis,-1,sizeof(dis)); q.push(s); dis[s]=0; while(!q.empty()) { int x=q.front(); q.pop(); for(int p=fst[x];~p;p=nxt[p]) { int y=e[p].v; if(dis[y]==-1&&e[p].cap>e[p].flow) { dis[y]=dis[x]+1; q.push(y); } } } return dis[t]!=-1; } int dfs(int x,int a) { int y,ret=0,f; if(x==t||!a)return a; for(int &p=cur[x];~p;p=nxt[p]) { y=e[p].v; if(dis[y]==dis[x]+1&&(f=dfs(y,min(e[p].cap-e[p].flow,a)))) { ret+=f; a-=f; e[p].flow+=f; e[p^1].flow-=f; if(!a)break; } } return ret; } void Dinic() { ans=0; while(bfs()) { for(int i=0;i<=t;i++) cur[i]=fst[i]; ans+=dfs(s,INF); } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&b[i]); pre(); tot=0; memset(fst,-1,sizeof(fst)); s=0,t=n+1+C; for(int i=1;i<=n;i++) if(dp[i]==1)build(s,i,INF); for(int i=1;i<=n;i++) { for(int j=0;j<i;j++) if(b[j]<b[i]&&dp[j]+1==dp[i]) build(j+C,i,INF); if(dp[i]==ma)build(i+C,t,INF); build(i,i+C,1); } Dinic(); printf("%d ",ans); } return 0; }
Smallest Minimum Cut
InputThe input contains several test cases and the first line is the total number of cases T (1≤T≤300)T (1≤T≤300).
Each case describes a network GG, and the first line contains two integers n (2≤n≤200)n (2≤n≤200) and m (0≤m≤1000)m (0≤m≤1000) indicating the sizes of nodes and edges. All nodes in the network are labelled from 11 to nn.
The second line contains two different integers ss and t (1≤s,t≤n)t (1≤s,t≤n) corresponding to the source and sink.
Each of the next mm lines contains three integers u,vu,v and w (1≤w≤255)w (1≤w≤255) describing a directed edge from node uu to vv with capacity ww.OutputFor each test case, output the smallest size of all minimum cuts in a line.Sample Input
2 4 5 1 4 1 2 3 1 3 1 2 3 1 2 4 1 3 4 2 4 5 1 4 1 2 3 1 3 1 2 3 1 2 4 1 3 4 3
Sample Output
2 3
求点s到点t的最小割 sap
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define MAXN 2333 #define MAXM 2333333 struct Edge { int v,next; ll cap; } edge[MAXM]; int head[MAXN],pre[MAXN],cur[MAXN],level[MAXN],gap[MAXN],NV,NE,n,m,vs,vt; void ADD(int u,int v,ll cap,ll cc=0) { edge[NE].v=v; edge[NE].cap=cap; edge[NE].next=head[u]; head[u]=NE++; edge[NE].v=u; edge[NE].cap=cc; edge[NE].next=head[v]; head[v]=NE++; } ll SAP(int vs,int vt) { memset(pre,-1,sizeof(pre)); memset(level,0,sizeof(level)); memset(gap,0,sizeof(gap)); for(int i=0; i<=NV; i++)cur[i]=head[i]; int u=pre[vs]=vs; ll aug=-1,maxflow=0; gap[0]=NV; while(level[vs]<NV) { loop: for(int &i=cur[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(edge[i].cap&&level[u]==level[v]+1) { aug==-1?aug=edge[i].cap:aug=min(aug,edge[i].cap); pre[v]=u; u=v; if(v==vt) { maxflow+=aug; for(u=pre[u]; v!=vs; v=u,u=pre[u]) { edge[cur[u]].cap-=aug; edge[cur[u]^1].cap+=aug; } aug=-1; } goto loop; } } int minlevel=NV; for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(edge[i].cap&&minlevel>level[v]) { cur[u]=i; minlevel=level[v]; } } if(--gap[level[u]]==0)break; level[u]=minlevel+1; gap[level[u]]++; u=pre[u]; } return maxflow; } int main() { int T,u,v,w; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); scanf("%d%d",&vs,&vt); NV=n,NE=0; memset(head,-1,sizeof(head)); for(int i=1; i<=m; i++) { scanf("%d%d%d",&u,&v,&w); ADD(u,v,(ll)w*MAXM+1); } ll ans=SAP(vs,vt); printf("%d ",ans%MAXM); } return 0; }
度度熊的交易计划
喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区。
由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但是最多生产b[i]个。
同样的,由于每个片区的购买能力的区别,第i个片区也能够以c[i]的价格出售最多d[i]个物品。
由于这些因素,度度熊觉得只有合理的调动物品,才能获得最大的利益。
据测算,每一个商品运输1公里,将会花费1元。
那么喵哈哈村最多能够实现多少盈利呢?
Input本题包含若干组测试数据。
每组测试数据包含:
第一行两个整数n,m表示喵哈哈村由n个片区、m条街道。
接下来n行,每行四个整数a[i],b[i],c[i],d[i]表示的第i个地区,能够以a[i]的价格生产,最多生产b[i]个,以c[i]的价格出售,最多出售d[i]个。
接下来m行,每行三个整数,u[i],v[i],k[i],表示该条公路连接u[i],v[i]两个片区,距离为k[i]
可能存在重边,也可能存在自环。
满足:
1<=n<=500,
1<=m<=1000,
1<=a[i],b[i],c[i],d[i],k[i]<=1000,
1<=u[i],v[i]<=n
Output输出最多能赚多少钱。
Sample Input
2 1 5 5 6 1 3 5 7 7 1 2 1
Sample Output
23
最小费用最大流。
首先建立超级源点 s
,与超级汇点 t
。
因为生产一个商品需要花费 a[i]
元,且上限为 b[i]
,所以我们从 s
向这些点之间连一条容量为 b[i]
,费用为 -a[i]
的边。
同样的道理,出售一个商品可以赚到 c[i]
元,最多出售 d[i]
个,于是我们从这些点向 t
连一条容量为 d[i]
,费用为 c[i]
的边。
最后所有的公路也是花费,从 u
到 v
连接一条双向边,容量为 INF
,费用为 -k
#include <bits/stdc++.h> using namespace std; const int maxn = 500+10; const int maxm = 400000+10; const int INF = 0x3f3f3f3f; int n, m; int a[maxn], b[maxn], c[maxn], d[maxn]; int Graph[maxn][maxn]; struct Edge { int v, c, w, next; Edge(){ } Edge(int v, int c, int w, int next) : v(v), c(c), w(w), next(next) {} }E[maxm]; queue<int> q; int H[maxn], cntE; int visit[maxn]; int cap[maxn]; int vis[maxn]; int dis[maxn]; int cur[maxn]; int flow, cost, s, t, T; void addedge(int u, int v, int c, int w) { E[cntE] = Edge(v, c, w, H[u]); H[u] = cntE++; E[cntE] = Edge(u, 0, -w, H[v]); H[v] = cntE++; } bool spfa() { memset(dis, INF, sizeof dis); cur[s] = -1; vis[s] = ++T; cap[s] = INF; dis[s] = 0; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = T - 1; for (int e = H[u]; ~e; e = E[e].next) { int v = E[e].v, c = E[e].c, w = E[e].w; if (c && dis[v] > dis[u] + w) { dis[v] = dis[u] + w; cap[v] = min(cap[u], c); cur[v] = e; if (vis[v] != T) { vis[v] = T; q.push(v); } } } } if (dis[t] > 0) return false; cost += cap[t] * dis[t]; flow += cap[t]; for (int e = cur[t]; ~e; e = cur[E[e ^ 1].v]) { E[e].c -= cap[t]; E[e ^ 1].c += cap[t]; } return true; } int main() { while(scanf("%d %d",&n,&m)!=EOF) { cntE=T=0; memset(H,-1,sizeof H); memset(vis,0,sizeof(vis)); for (int i = 1; i <= n; i++) { scanf("%d %d %d %d",a+i,b+i,c+i,d+i); } s = 0; t = n + 1; for (int i = 0; i <= n + 1; i++) for (int j = 0; j <= n + 1; j++) { if (i == j) Graph[i][j] = 0; else Graph[i][j] = INF; } for (int i = 1; i <= m; i++) { int t1, t2, t3; scanf("%d%d%d", &t1, &t2, &t3); if (Graph[t1][t2] > t3) { Graph[t1][t2] = Graph[t2][t1] = t3; } } for (int i = 1; i <= n; i++) { addedge(i, t, b[i], a[i]); addedge(s, i, d[i], -c[i]); } for(int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { if (i != j && Graph[i][j] != INF) { addedge(i, j, INF, Graph[i][j]); } } flow = cost = 0; while (spfa()); int ans = -cost; printf("%d ", ans); } return 0; }
2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 J. Our Journey of Dalian Ends
Life is a journey, and the road we travel has twists and turns, which sometimes lead us to unexpected places and unexpected people.
Now our journey of Dalian ends. To be carefully considered are the following questions.
Next month in Xian, an essential lesson which we must be present had been scheduled.
But before the lesson, we need to attend a wedding in Shanghai.
We are not willing to pass through a city twice.
All available expressways between cities are known.
What we require is the shortest path, from Dalian to Xian, passing through Shanghai.
Here we go.
Input Format
There are several test cases.
The first line of input contains an integer ttwhich is the total number of test cases.
For each test case, the first line contains an integer m~(mle 10000)m (m≤10000) which is the number of known expressways.
Each of the following mm lines describes an expressway which contains two string indicating the names of two cities and an integer indicating the length of the expressway.
The expressway connects two given cities and it is bidirectional.
Output Format
For eact test case, output the shortest path from Dalian to Xian, passing through Shanghai, or output -1−1 if it does not exist.
样例输入
3 2 Dalian Shanghai 3 Shanghai Xian 4 5 Dalian Shanghai 7 Shanghai Nanjing 1 Dalian Nanjing 3 Nanjing Xian 5 Shanghai Xian 8 3 Dalian Nanjing 6 Shanghai Nanjing 7 Nanjing Xian 8
样例输出
7 12 -1
给定若干个城市,出发点为大连,目的地为西安,但是要求中途必须经过上海,并且图中每个城市只能经过一次,给出m条路(双向道路),走第i条路需要wi代价,求所有满足要求的方案中花费的最小代价,如果没有满足的方案,输出-1。
上海的容量必须是2,不是2就输出-1
#include<bits/stdc++.h> using namespace std; const int N=1e4+5; const int M=1e5+5; const int INF=0x3f3f3f3f; int FIR[N],TO[M],CAP[M],FLOW[M],COST[M],NEXT[M],tote; int pre[N],dist[N],q[400000]; bool vis[N]; void add(int u,int v,int cap,int cost) { TO[tote]=v; CAP[tote]=cap; FLOW[tote]=0; COST[tote]=cost; NEXT[tote]=FIR[u]; FIR[u]=tote++; TO[tote]=u; CAP[tote]=0; FLOW[tote]=0; COST[tote]=-cost; NEXT[tote]=FIR[v]; FIR[v]=tote++; } bool SPFA(int s, int t) { memset(dist,INF,sizeof(dist)); memset(vis,false,sizeof(vis)); memset(pre,-1,sizeof(pre)); dist[s] = 0;vis[s]=true;q[1]=s; int head=0,tail=1; while(head!=tail) { int u=q[++head];vis[u]=false; for(int v=FIR[u];v!=-1;v=NEXT[v]) { if(dist[TO[v]]>dist[u]+COST[v]&&CAP[v]>FLOW[v]) { dist[TO[v]]=dist[u]+COST[v]; pre[TO[v]]=v; if(!vis[TO[v]]) { vis[TO[v]] = true; q[++tail]=TO[v]; } } } } return pre[t]!=-1; } void MCMF(int s, int t, int &cost, int &flow) { flow=cost=0; while(SPFA(s,t)) { int Min=INF; for(int v=pre[t];v!=-1;v=pre[TO[v^1]]) Min=min(Min, CAP[v]-FLOW[v]); for(int v=pre[t];v!=-1;v=pre[TO[v^1]]) { FLOW[v]+=Min;FLOW[v^1]-=Min; cost+=COST[v]*Min; } flow+=Min; } } int tot,Xian,Shanghai,Dalian; map<string,int>MP; int la(string s) { if(!MP.count(s))MP[s]=++tot; if(s=="Xian") Xian=MP[s]; if(s=="Shanghai") Shanghai=MP[s]; if(s=="Dalian") Dalian=MP[s]; return MP[s]; } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int T,m; cin>>T; while(T--) { tot=0,tote=0,memset(FIR,-1,sizeof(FIR)),MP.clear(); cin>>m; string s1,s2; for(int i=0,u,v,w;i<m;i++) { cin>>s1>>s2>>w; u=la(s1),v=la(s2); add(2*u,2*v-1,1,w),add(2*v,2*u-1,1,w); } for(int i=1; i<=tot; i++) { if(i==Shanghai) add(2*i-1,2*i,2,0); else add(2*i-1,2*i,1,0); } add(0,Xian*2-1,1,0); add(0,Dalian*2-1,1,0); int flow,cost; MCMF(0,Shanghai*2,cost,flow); if(flow==2)cout<<cost<<" "; else cout<<"-1 "; } return 0; }
有意思的是去年青岛现场也有一道类似的题目
这篇博客的代码应该是比较清晰的
Our Journey of Xian Ends
题目地址:https://nanti.jisuanke.com/t/18521
Life is a journey, and the road we travel has twists and turns, which sometimes lead us to unexpected places and unexpected people. Now our journey of Xian ends. To be carefully considered are the following questions.
A few months later in Qingdao, an essential ACM competition had been scheduled. But before the competition, we need to attend a wedding in Shanghai. And after the competition, we will leave the country from Shanghai, so Pudong International Airport (Pudong in short) is the end of our tour.
Here we have some vital information and missions we have to accomplish.
We have a VIP card of CNAC. For each airport we can enjoy the special VIP services in the departure floor and the arrival floor once respectively. For the pleasure of traveling, it is intolerant without VIP services. That is say that for each airport we can leave from it only once, but without regard to the last flight leaving the country from Pudong, Shanghai. Meanwhile, for each airport we can arrive at it only once.
All as we know, Shanghai has two airports, Hongqiao Airport (Hongqiao in short) and Pudong. Arriving at one and then leaving from another one is a spurned thing. But fortunately there is a nice and evil compensation service. Having a pair of transfer records between Hongqiao and Pudong in both directions, we can obtain a sensible compensation. Actually, we only consider planes in our tour, with the only exception in Shanghai. The exception is that we can arrive and leave Shanghai at different airports. However, if we decide so the compensation described above is necessary. Before the end of our tour, we will pass through Shanghai twice, once for the wedding and another time for the final departure. If we want to obtain the compensation, in the first time we must transfer from Pudong to Hongqiao, and in the second time we will transfer from Hongqiao to Pudong.
Similar transfers between airports in other city are not allowed. If we arrived at a city, we would not go to an airport in an adjacent city by car, bus or interurban railway as well.
Now, all available flights between airports are known. We have plenty of time yet. So we do not have any restriction about the number of times. What we require is the smallest total cost of flights throughout the whole tour.
Here we go.
Input
There are several test cases. The first line of input contains an integer t (1 ≤ t ≤ 160) which is the total number of test cases. For each test case, the first line contains an integer m (m ≤ 10000) which is the number of known flights. Each of the following m lines describes a flight which contains two string indicating the names of two airports and an integer between 1 and 255 indicating the cost. The flight connects two given airports and it is bidirectional. The name of each airport is an non-empty string with English letters that are no longer than 10. We use “Xian” to present the only airport in Xian, and use “Qingdao” to present the only airport in Qingdao. The airports in Shanghai are described as “Hongqiao” and “Pudong” respectively.
Output
For each test case, output the smallest total cost, or output −1 if it is impossible.
样例输入
3 4 Xian Hongqiao 3 Xian Pudong 4 Qingdao Hongqiao 4 Qingdao Pudong 3 4 Xian Hongqiao 4 Xian Pudong 3 Qingdao Hongqiao 3 Qingdao Pudong 4 6 Xian Hongqiao 4 Xian Pudong 3 Qingdao Hongqiao 3 Qingdao Pudong 4 Qingdao Xuzhou 1 Xuzhou Hongqiao 1
样例输出
10 9 8
题目来源
这个事要经过上海,但是上海呢,有两个机场,又有新的限制
AC代码
#include<bits/stdc++.h> using namespace std; const int N=5e4+5; const int M=1e5+5; const int INF=0x3f3f3f3f; int FIR[N],TO[M],CAP[M],FLOW[M],COST[M],NEXT[M],tote; int pre[N],dist[N],q[800000]; bool vis[N]; void add(int u,int v,int cap,int cost) { TO[tote]=v; CAP[tote]=cap; FLOW[tote]=0; COST[tote]=cost; NEXT[tote]=FIR[u]; FIR[u]=tote++; TO[tote]=u; CAP[tote]=0; FLOW[tote]=0; COST[tote]=-cost; NEXT[tote]=FIR[v]; FIR[v]=tote++; } bool SPFA(int s, int t) { memset(dist,INF,sizeof(dist)); memset(vis,false,sizeof(vis)); memset(pre,-1,sizeof(pre)); dist[s] = 0; vis[s]=true; q[1]=s; int head=0,tail=1; while(head!=tail) { int u=q[++head]; vis[u]=false; for(int v=FIR[u]; v!=-1; v=NEXT[v]) { if(dist[TO[v]]>dist[u]+COST[v]&&CAP[v]>FLOW[v]) { dist[TO[v]]=dist[u]+COST[v]; pre[TO[v]]=v; if(!vis[TO[v]]) { vis[TO[v]] = true; q[++tail]=TO[v]; } } } } return pre[t]!=-1; } void MCMF(int s, int t, int &cost, int &flow) { flow=cost=0; while(SPFA(s,t)) { int Min=INF; for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) Min=min(Min, CAP[v]-FLOW[v]); for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) { FLOW[v]+=Min; FLOW[v^1]-=Min; cost+=COST[v]*Min; } flow+=Min; } } int tot,Xian,Qingdao,Hongqiao,Pudong; map<string,int>MP; int la(string s) { if(MP.count(s))return MP[s]; MP[s]=++tot; add(tot*2-1,tot*2,1,0); return MP[s]; } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int T,n; cin>>T; while(T--) { tot=0,tote=0,memset(FIR,-1,sizeof(FIR)),MP.clear(); cin>>n; string s1,s2; MP["Xian"]=++tot; add(tot*2-1,tot*2,1,0); MP["Qingdao"]=++tot; add(tot*2-1,tot*2,2,0); MP["Hongqiao"]=++tot; add(tot*2-1,tot*2,2,0); MP["Pudong"]=++tot; add(tot*2-1,tot*2,1,0); for(int i=0,u,v,w; i<n; i++) { cin>>s1>>s2>>w; u=la(s1),v=la(s2); add(2*u,2*v-1,INF,w),add(2*v,2*u-1,INF,w); } add(0,3*2-1,2,0); add(0,4*2-1,1,0); add(1*2,2*tot+1,1,0); add(2*2,2*tot+1,2,0); int flow,cost; MCMF(0,2*tot+1,cost,flow); if(flow==3)cout<<cost<<" "; else cout<<"-1 "; } return 0; }
这份代码建图更清晰
#include<bits/stdc++.h> using namespace std; const int N=5e4+5; const int M=1e5+5; const int INF=0x3f3f3f3f; int FIR[N],TO[M],CAP[M],FLOW[M],COST[M],NEXT[M],tote; int pre[N],dist[N],q[800000]; bool vis[N]; void add(int u,int v,int cap,int cost) { TO[tote]=v; CAP[tote]=cap; FLOW[tote]=0; COST[tote]=cost; NEXT[tote]=FIR[u]; FIR[u]=tote++; TO[tote]=u; CAP[tote]=0; FLOW[tote]=0; COST[tote]=-cost; NEXT[tote]=FIR[v]; FIR[v]=tote++; } bool SPFA(int s, int t) { memset(dist,INF,sizeof(dist)); memset(vis,false,sizeof(vis)); memset(pre,-1,sizeof(pre)); dist[s] = 0; vis[s]=true; q[1]=s; int head=0,tail=1; while(head!=tail) { int u=q[++head]; vis[u]=false; for(int v=FIR[u]; v!=-1; v=NEXT[v]) { if(dist[TO[v]]>dist[u]+COST[v]&&CAP[v]>FLOW[v]) { dist[TO[v]]=dist[u]+COST[v]; pre[TO[v]]=v; if(!vis[TO[v]]) { vis[TO[v]] = true; q[++tail]=TO[v]; } } } } return pre[t]!=-1; } void MCMF(int s, int t, int &cost, int &flow) { flow=cost=0; while(SPFA(s,t)) { int Min=INF; for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) Min=min(Min, CAP[v]-FLOW[v]); for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) { FLOW[v]+=Min; FLOW[v^1]-=Min; cost+=COST[v]*Min; } flow+=Min; } } int tot,Xian,Qingdao,Hongqiao,Pudong; map<string,int>MP; int la(string s) { if(!MP.count(s))MP[s]=++tot; if(s=="Xian") Xian=MP[s]; if(s=="Qingdao") Qingdao=MP[s]; if(s=="Hongqiao") Hongqiao=MP[s]; if(s=="Pudong")Pudong=MP[s]; return MP[s]; } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int T,n; cin>>T; while(T--) { tot=0,tote=0,memset(FIR,-1,sizeof(FIR)),MP.clear(); cin>>n; string s1,s2; Xian=Qingdao=Hongqiao=Pudong=-1; for(int i=0,u,v,w; i<n; i++) { cin>>s1>>s2>>w; u=la(s1),v=la(s2); add(2*n+u,v,INF,w),add(2*n+v,u,INF,w); } for(int i=1; i<=tot; i++) { if(i==Xian)add(i+2*n,4*n+1,1,0),add(i,i+2*n,1,0); else if(i==Qingdao) add(i+2*n,4*n+1,2,0),add(i,i+2*n,2,0); else if(i==Hongqiao) add(0,i,2,0),add(i,i+2*n,2,0); else if(i==Pudong) add(0,i,1,0),add(i,i+2*n,1,0); else add(i,i+2*n,1,0); } int flow,cost; MCMF(0,4*n+1,cost,flow); if(flow==3)cout<<cost<<" "; else cout<<"-1 "; } return 0; }
4712: Double Shortest Paths
时间限制(普通/Java):1000MS/3000MS 内存限制:65536KByte
总提交: 11 测试通过:4
描述
Alice and Bob are walking in an ancient maze with a lot of caves and one-way passages connecting them. They want to go from cave 1 to cave n. All the passages are difficult to pass. Passages are too small for two people to walk through simultaneously, and crossing a passage can make it even more difficult to pass for the next person. We define di as the difficulty of crossing passage i for the first time, and ai as the additional difficulty for the second time (e.g. the second person's difficulty is di+ai).
Your task is to find two (possibly identical) routes for Alice and Bob, so that their total difficulty is minimized.
For example, in figure 1, the best solution is 1->2->4 for both Alice and Bob, but in figure 2, it's better to use 1->2->4 for Alice and 1->3->4 for Bob.
输入
There will be at most 200 test cases. Each case begins with two integers n, m (1<=n<=500, 1<=m<=2000), the number of caves and passages. Each of the following m lines contains four integers u, v, di and ai (1<=u,v<=n, 1<=di<=1000, 0<=ai<=1000). Note that there can be multiple passages connecting the same pair of caves, and even passages connecting a cave and itself.
输出
For each test case, print the case number and the minimal total difficulty.
样例输入
4 4
1 2 5 1
2 4 6 0
1 3 4 0
3 4 9 1
4 4
1 2 5 10
2 4 6 10
1 3 4 10
3 4 9 10
样例输出
Case 1: 23
Case 2: 24
题目来源
继续最小费用最大流,u ,v 构一条费用为 w 流量为1 。一条为w + a ,流量也为1的边然后源和汇到1 , n的费用为0,流量为2
#include<bits/stdc++.h> using namespace std; const int N=1e4+5; const int M=1e5+5; const int INF=0x3f3f3f3f; int FIR[N],TO[M],CAP[M],FLOW[M],COST[M],NEXT[M],tote; int pre[N],dist[N],q[400000]; bool vis[N]; int n,m,S,T; void init() { tote=0; memset(FIR,-1,sizeof(FIR)); } void add(int u,int v,int cap,int cost) { TO[tote]=v; CAP[tote]=cap; FLOW[tote]=0; COST[tote]=cost; NEXT[tote]=FIR[u]; FIR[u]=tote++; TO[tote]=u; CAP[tote]=0; FLOW[tote]=0; COST[tote]=-cost; NEXT[tote]=FIR[v]; FIR[v]=tote++; } bool SPFA(int s, int t) { memset(dist,INF,sizeof(dist)); memset(vis,false,sizeof(vis)); memset(pre,-1,sizeof(pre)); dist[s] = 0;vis[s]=true;q[1]=s; int head=0,tail=1; while(head!=tail) { int u=q[++head];vis[u]=false; for(int v=FIR[u];v!=-1;v=NEXT[v]) { if(dist[TO[v]]>dist[u]+COST[v]&&CAP[v]>FLOW[v]) { dist[TO[v]]=dist[u]+COST[v]; pre[TO[v]]=v; if(!vis[TO[v]]) { vis[TO[v]] = true; q[++tail]=TO[v]; } } } } return pre[t]!=-1; } void MCMF(int s, int t, int &cost, int &flow) { flow=cost=0; while(SPFA(s,t)) { int Min=INF; for(int v=pre[t];v!=-1;v=pre[TO[v^1]]) Min=min(Min, CAP[v]-FLOW[v]); for(int v=pre[t];v!=-1;v=pre[TO[v^1]]) { FLOW[v]+=Min;FLOW[v^1]-=Min; cost+=COST[v]*Min; } flow+=Min; } } int main() { int ca=0; while(~scanf("%d%d",&n,&m)) { init(); S = 0; T = n + 1; for (int i = 0,u,v,c,a; i < m; i++) { scanf("%d%d%d%d", &u, &v, &c,&a); add(u, v, 1, c); add(u, v, 1, c+a); } add(S, 1, 2, 0); add(n, T, 2, 0); int cost,flow; MCMF(S,T,cost,flow); printf("Case %d: %d ",++ca,cost); } return 0; }
多校
L - Problem L.Videos
For simplicity’s sake, they will be called as videoA and videoB.
There are some people who want to watch videos during today, and they will be happy after watching videos of C-bacteria.
There are n hours a day, m videos are going to be show, and the number of people is K.
Every video has a type(videoA or videoB), a running time, and the degree of happi- ness after someone watching whole of it.
People can watch videos continuous(If one video is running on 2pm to 3pm and another is 3pm to 5pm, people can watch both of them).
But each video only allows one person for watching.
For a single person, it’s better to watch two kinds to videos alternately, or he will lose W happiness.
For example, if the order of video is ’videoA, videoB, videoA, videoB, …’ or ’B, A, B, A, B, …’, he won’t lose happiness; But if the order of video is ’A, B, B, B, A, B, A, A’, he will lose 3W happiness.
Now you have to help people to maximization the sum of the degree of happiness.
InputMultiple query.
On the first line, there is a positive integer T, which describe the number of data. Next there are T groups of data.
for each group, the first line have four positive integers n, m, K, W : n hours a day, m videos, K people, lose W happiness when watching same videos).
and then, the next m line will describe m videos, four positive integers each line S, T, w, op : video is the begin at S and end at T, the happiness that people can get is w, and op describe it’s tpye(op=0 for videoA and op=1 for videoB).
There is a blank line before each groups of data.
T<=20, n<=200, m<=200, K<=200, W<=20, 1<=S<T<=n, W<=w<=1000,
op=0 or op=1
OutputYour output should include T lines, for each line, output the maximum happiness for the corresponding datum.Sample Input
2 10 3 1 10 1 5 1000 0 5 10 1000 1 3 9 10 0 10 3 1 10 1 5 1000 0 5 10 1000 0 3 9 10 0
Sample Output
2000 1990
按照时间建图
#include<bits/stdc++.h> using namespace std; const int N=1e4+5; const int M=1e5+5; const int INF=0x3f3f3f3f; int FIR[N],TO[M],CAP[M],FLOW[M],COST[M],NEXT[M],tote; int pre[N],dist[N],q[400000]; bool vis[N]; void init() { tote=0; memset(FIR,-1,sizeof(FIR)); } void add(int u,int v,int cap,int cost) { TO[tote]=v; CAP[tote]=cap; FLOW[tote]=0; COST[tote]=cost; NEXT[tote]=FIR[u]; FIR[u]=tote++; TO[tote]=u; CAP[tote]=0; FLOW[tote]=0; COST[tote]=-cost; NEXT[tote]=FIR[v]; FIR[v]=tote++; } bool SPFA(int s, int t) { memset(dist,INF,sizeof(dist)); memset(vis,false,sizeof(vis)); memset(pre,-1,sizeof(pre)); dist[s] = 0; vis[s]=true; q[1]=s; int head=0,tail=1; while(head!=tail) { int u=q[++head]; vis[u]=false; for(int v=FIR[u]; v!=-1; v=NEXT[v]) { if(dist[TO[v]]>dist[u]+COST[v]&&CAP[v]>FLOW[v]) { dist[TO[v]]=dist[u]+COST[v]; pre[TO[v]]=v; if(!vis[TO[v]]) { vis[TO[v]] = true; q[++tail]=TO[v]; } } } } return pre[t]!=-1; } void MCMF(int s, int t, int &cost, int &flow) { flow=cost=0; while(SPFA(s,t)) { int Min=INF; for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) Min=min(Min, CAP[v]-FLOW[v]); for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) { FLOW[v]+=Min; FLOW[v^1]-=Min; cost+=COST[v]*Min; } flow+=Min; } } struct T { int l,r,w,tp; } a[1505]; int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int ca; cin>>ca; while(ca--) { init(); int n,m,K,W; cin>>n>>m>>K>>W; add(0,m+m+2,K,0); add(m+m+3,m+m+1,K,0); for(int i=1; i<=m; i++)cin>>a[i].l>>a[i].r>>a[i].w>>a[i].tp; for(int i=1; i<=m; i++) for(int j=1; j<=m; j++) { if(i==j)continue; if(a[i].r<=a[j].l)add(i+m,j,1,(a[i].tp==a[j].tp?W:0)); } for(int i=1; i<=m; i++) add(i,i+m,1,-a[i].w),add(m+m+2,i,1,0),add(i+m,m+m+3,1,0); int cost,flow; MCMF(0,m+m+1,cost,flow); cout<<-cost<<" "; } return 0; }
上海邀请赛
链接:https://www.nowcoder.com/acm/contest/163/I
来源:牛客网
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
The grid in (i,j) (0 ≤ i < N, 0 ≤ j < M) has Aij balls.
In each operation you can remove one ball from a grid or add one ball into a grid.
The goal of this game is to make each of the rows has the same number of balls and each of the columns has the same number of balls.
What is the minumun operations you should use?
输入描述:
The first line of the input is T(1≤ T ≤ 100), which stands for the number of test cases you need to solve.ij
The first line of each test case contains two integers N and M (1 ≤ N,M ≤ 20).
The next N lines describe A
, each line contains M integers. (0 ≤ Aij
≤ 20).
输出描述:
For each test case, print the case number and the answer.
说明
for the first example, the number of balls after operations is
4 6 5
6 4 5
卡了100年的超时,最后靠别人代码的模板过了
#include<bits/stdc++.h> using namespace std; const int INF=0x3f3f3f3f; int n,m,a[25][25],S,T; int cnt=0,head[1000],dis[1000],cur[1000]; struct Edge { int nxt,to, val; } edge[1000]; void add(int p,int q,int c) { edge[cnt].to=q; edge[cnt].val=c; edge[cnt].nxt=head[p]; head[p]=cnt++; edge[cnt].to=p; edge[cnt].val=0; edge[cnt].nxt=head[q]; head[q]=cnt++; } bool bfs() { memset(dis,-1,sizeof dis); dis[S]=0; queue<int>que; que.push(S); while(!que.empty()) { int u=que.front(); if(u==T)return true; que.pop(); for(int i=head[u]; ~i; i=edge[i].nxt) { int v=edge[i].to; if(edge[i].val>0&&dis[v]==-1) { que.push(v); dis[v]=dis[u]+1; } } } return false; } int dfs(int u,int flow) { if(u==T||flow==0)return flow; int res=0,f; for(int &i=cur[u]; ~i; i=edge[i].nxt) { int v=edge[i].to; int val=edge[i].val; if(dis[v] == dis[u]+1 && (f=dfs(v,min(flow-res,val))) > 0 ) { edge[i].val-=f; edge[i^1].val+=f; res+=f; if(res==flow)return res; } } if(!res)dis[u]=-1; return res; } int dinic() { int res=0; while(bfs()) { memcpy(cur,head,sizeof head); res+=dfs(S,INF); } return res; } int main() { int ca=0,t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); int sum=0; for(int i=0; i<n; i++) for(int j=0; j<m; j++) scanf("%d",&a[i][j]),sum+=a[i][j]; int lcm=n/__gcd(n,m)*m,ans=INF; S=n+m,T=n+m+1; for(int x=0; x<=20*n*m; x+=lcm) { cnt=0,memset(head,-1,sizeof(head)); for(int i=0; i<n; i++)add(S,i,x/n); for(int i=0; i<m; i++)add(n+i,T,x/m); for(int i=0; i<n; i++) for(int j=0; j<m; j++)add(i,n+j,a[i][j]); ans=min(ans,x+sum-dinic()*2); } printf("Case %d: %d ",++ca,ans); } return 0; }
BZOJ
1061: [Noi2008]志愿者招募
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 5834 Solved: 3510
[Submit][Status][Discuss]
Description
Input
Output
仅包含一个整数,表示你所设计的最优方案的总费用。
Sample Input
2 3 4
1 2 2
2 3 5
3 3 2
Sample Output
HINT
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。
#include<iostream> #include<string.h> #include<queue> using namespace std; const int N=1e4+5; const int M=1e5+5; const int INF=0x3f3f3f3f; int FIR[N],TO[M],CAP[M],FLOW[M],COST[M],NEXT[M],tote; int pre[N],dist[N],q[400000]; bool vis[N]; void init() { tote=0; memset(FIR,-1,sizeof(FIR)); } void add(int u,int v,int cap,int cost) { TO[tote]=v; CAP[tote]=cap; FLOW[tote]=0; COST[tote]=cost; NEXT[tote]=FIR[u]; FIR[u]=tote++; TO[tote]=u; CAP[tote]=0; FLOW[tote]=0; COST[tote]=-cost; NEXT[tote]=FIR[v]; FIR[v]=tote++; } bool SPFA(int s, int t) { memset(dist,INF,sizeof(dist)); memset(vis,false,sizeof(vis)); memset(pre,-1,sizeof(pre)); dist[s] = 0; vis[s]=true; q[1]=s; int head=0,tail=1; while(head!=tail) { int u=q[++head]; vis[u]=false; for(int v=FIR[u]; v!=-1; v=NEXT[v]) { if(dist[TO[v]]>dist[u]+COST[v]&&CAP[v]>FLOW[v]) { dist[TO[v]]=dist[u]+COST[v]; pre[TO[v]]=v; if(!vis[TO[v]]) { vis[TO[v]] = true; q[++tail]=TO[v]; } } } } return pre[t]!=-1; } void MCMF(int s, int t, int &cost, int &flow) { flow=cost=0; while(SPFA(s,t)) { int Min=INF; for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) Min=min(Min, CAP[v]-FLOW[v]); for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) { FLOW[v]+=Min; FLOW[v^1]-=Min; cost+=COST[v]*Min; } flow+=Min; } } int a[1005]; int main() { init(); int n,m; cin>>n>>m; for(int i=1; i<=n; i++)cin>>a[i]; for(int i=1,a,b,c; i<=m; i++)cin>>a>>b>>c,add(a,b+1,INF,c); for(int i=1,x; i<=n+1; i++) { x=a[i]-a[i-1]; if(x>=0) add(0,i,x,0); else add(i,n+2,-x,0); if(i>1) add(i,i-1,INF,0); } int cost,flow; MCMF(0,n+2,cost,flow); cout<<cost<<" "; return 0; }
A Birthday
链接:https://www.nowcoder.com/acm/contest/206/A
来源:牛客网
空间限制:C/C++ 1048576K,其他语言2097152K
64bit IO Format: %lld
题目描述
正如往常一样,宇扬在蛋糕上插了n支蜡烛,并把蛋糕分为m个区域。因为某种原因,他必须把第i根蜡烛插在第ai个区域或第bi个区域。区域之间是不相交的。宇扬在一个区域内同时摆放x支蜡烛就要花费x2的时间。宇扬布置蛋糕所用的总时间是他在每个区域花的时间的和。
宇扬想快些见到恬恬,你能告诉他布置蛋糕最少需要多少时间吗?
输入描述:
第一行包含两个整数n,m(1 ≤ n ≤ 50, 2≤ m≤ 50)。i
接下来n行,每行两个整数a
,bi
(1 ≤ ai
, bi
≤ m)。
输出描述:
一个整数表示答案。
#include<bits/stdc++.h> using namespace std; const int N=1e4+5; const int M=1e5+5; const int INF=0x3f3f3f3f; int FIR[N],TO[M],CAP[M],FLOW[M],COST[M],NEXT[M],tote; int pre[N],dist[N],q[400000]; bool vis[N]; int n,m,S,T; void init() { tote=0; memset(FIR,-1,sizeof(FIR)); } void add(int u,int v,int cap,int cost) { TO[tote]=v; CAP[tote]=cap; FLOW[tote]=0; COST[tote]=cost; NEXT[tote]=FIR[u]; FIR[u]=tote++; TO[tote]=u; CAP[tote]=0; FLOW[tote]=0; COST[tote]=-cost; NEXT[tote]=FIR[v]; FIR[v]=tote++; } bool SPFA(int s, int t) { memset(dist,INF,sizeof(dist)); memset(vis,false,sizeof(vis)); memset(pre,-1,sizeof(pre)); dist[s] = 0; vis[s]=true; q[1]=s; int head=0,tail=1; while(head!=tail) { int u=q[++head]; vis[u]=false; for(int v=FIR[u]; v!=-1; v=NEXT[v]) { if(dist[TO[v]]>dist[u]+COST[v]&&CAP[v]>FLOW[v]) { dist[TO[v]]=dist[u]+COST[v]; pre[TO[v]]=v; if(!vis[TO[v]]) { vis[TO[v]] = true; q[++tail]=TO[v]; } } } } return pre[t]!=-1; } void MCMF(int s, int t, int &cost, int &flow) { flow=cost=0; while(SPFA(s,t)) { int Min=INF; for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) Min=min(Min, CAP[v]-FLOW[v]); for(int v=pre[t]; v!=-1; v=pre[TO[v^1]]) { FLOW[v]+=Min; FLOW[v^1]-=Min; cost+=COST[v]*Min; } flow+=Min; } } int main() { scanf("%d%d",&n,&m); init(); S=0; T=n+m+1; for(int i=1,u,v; i<=n; i++) { scanf("%d%d",&u,&v); add(0,i,1,0),add(i,u+n,1,0),add(i,v+n,1,0); } for(int i=1;i<=m;i++) for(int j=1;j<=99;j+=2)add(i+n,n+m+1,1,j); int cost,flow; MCMF(S,T,cost,flow); printf("%d ",cost); }