网络流专题(完结撒花)

题目及链接地址

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 分享至QQ空间

Time Limit(Common/Java):1000MS/3000MS     Memory Limit:65536KByte
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\n",ans);
    }
    return 0;
}

 

1625: Secret Milking Machine 分享至QQ空间

Time Limit(Common/Java):1000MS/10000MS     Memory Limit:65536KByte
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

Farmer John can travel trails 1 - 2 - 3 - 7 and 1 - 6 - 7. None of the trails travelled exceeds 5 units in length. It is impossible for Farmer John to travel from 1 to 7 twice without using at least one trail of length 5. 

Huge input data,scanf is recommended.
你找出T条每条边都边不重复的路径,使得的这T条路径中的每段路径的最大值最小,求出这个最大值。
二分+sap
#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\n",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 分享至QQ空间

Time Limit(Common/Java):1000MS/3000MS     Memory Limit:65536KByte
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\n",ans);
    }
    return 0;
}

Smallest Minimum Cut

Consider a network G=(V,E)G=(V,E) with source ss and sink tt. An s-t cut is a partition of nodes set VV into two parts such that ss and tt belong to different parts. The cut set is the subset of EE with all edges connecting nodes in different parts. A minimum cut is the one whose cut set has the minimum summation of capacities. The size of a cut is the number of edges in the cut set. Please calculate the smallest size of all minimum cuts.

InputThe input contains several test cases and the first line is the total number of cases T (1T300)T (1≤T≤300). 
Each case describes a network GG, and the first line contains two integers n (2n200)n (2≤n≤200) and m (0m1000)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 (1s,tn)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 (1w255)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\n",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\n", 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~(m\le 10000)m (m10000) 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 -11 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<<"\n";
        else cout<<"-1\n";
    }
    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

题目来源

ACM-ICPC 2017 Asia Qingdao

这个事要经过上海,但是上海呢,有两个机场,又有新的限制

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<<"\n";
        else cout<<"-1\n";
    }
    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<<"\n";
        else cout<<"-1\n";
    }
    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

题目来源

2014湖南省第十届大学生程序设计竞赛

继续最小费用最大流,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\n",++ca,cost);
    }
    return 0;
}

 

多校

L - Problem L.Videos

 HDU - 6437

C-bacteria takes charge of two kinds of videos: ’The Collection of Silly Games’ and ’The Collection of Horrible Games’. 
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<<"\n";
    }
    return 0;
}

上海邀请赛

链接:https://www.nowcoder.com/acm/contest/163/I
来源:牛客网

Matrix Game
时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

At the start of the matrix game, we have an N x M matrix. Each grid has some balls.
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.
The first line of each test case contains two integers N and M (1 ≤ N,M ≤ 20).
The next N lines describe A
ij
, each line contains M integers. (0 ≤ A
ij
 ≤ 20).

输出描述:

For each test case, print the case number and the answer.
示例1

输入

复制
2
2 3
4 8 5
2 4 6
3 3
1 5 2
3 5 4
2 3 4

输出

复制
Case 1: 7
Case 2: 7

说明

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\n",++ca,ans);
    }
    return 0;
}

 BZOJ

1061: [Noi2008]志愿者招募

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 5834  Solved: 3510
[Submit][Status][Discuss]

Description

 

  申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难
题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要
Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用
是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这
并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。

Input

  第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负
整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了
方便起见,我们可以认为每类志愿者的数量都是无限多的。

Output

  仅包含一个整数,表示你所设计的最优方案的总费用。

Sample Input

3 3
2 3 4
1 2 2
2 3 5
3 3 2

Sample Output

14

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<<"\n";
    return 0;
}

 A Birthday

链接:https://www.nowcoder.com/acm/contest/206/A
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 1048576K,其他语言2097152K
64bit IO Format: %lld

题目描述

恬恬的生日临近了。宇扬给她准备了一个蛋糕。
正如往常一样,宇扬在蛋糕上插了n支蜡烛,并把蛋糕分为m个区域。因为某种原因,他必须把第i根蜡烛插在第ai个区域或第bi个区域。区域之间是不相交的。宇扬在一个区域内同时摆放x支蜡烛就要花费x2的时间。宇扬布置蛋糕所用的总时间是他在每个区域花的时间的和。
宇扬想快些见到恬恬,你能告诉他布置蛋糕最少需要多少时间吗?

输入描述:

第一行包含两个整数n,m(1 ≤ n ≤ 50, 2≤ m≤ 50)。
接下来n行,每行两个整数a
i
,b
i
(1 ≤ a
i
, b
i
 ≤ m)。

输出描述:

一个整数表示答案。
示例1

输入

复制
3 3
1 2
1 2
1 2

输出

复制
5
示例2

输入

复制
3 3
1 2
2 3
1 3

输出

复制
3
 把每个part拆成n个点
#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\n",cost);
}

 

 
posted @ 2018-09-06 19:46  暴力都不会的蒟蒻  阅读(529)  评论(0编辑  收藏  举报