zoukankan      html  css  js  c++  java
  • 图论例题合集(三)

    目录

     

    A:LightOJ - 1156 Jumping Frogs

    B:LightOJ - 1167 Dangerous Tunnels

    C:LightOJ - 1176 Getting a T-shirt

    D:LightOJ - 1177 Angry Programmer

    E:LightOJ - 1405 The Great Escape

    F:LightOJ - 1071 Baker Vai

    G:LightOJ - 1222 Gift Packing

    H:LightOJ - 1237 Cyber Cafe


    A:LightOJ - 1156 Jumping Frogs:题意:给定一段宽为m的河道,在河道中有n个石头排成一条直线,石头分两种:B种石头可以踩无限多次,S种石头只能踩一次。现在要在河道中来回一次,也就是过河两次,求单次所走最大距离的最小值 思路:之前做过类似的题目,不过这题更麻烦一点。因为S种石头只能踩一次,所以要拆点连边,容量为1,为了方便,对B种石头也顺便拆点,容量大于1即可(但不要太大,会发生悲剧-_-||),然后二分枚举最大距离,小于等于枚举值的边就连上,容量大于1,源点汇点分别为河的左右边,注意源点汇点距离小于等于枚举值时,也要连上,此时最大流的意义就是通过河道有几条通路,大于等于2时说明枚举值满足题目条件,接下不断枚举,直到找到最小的满足条件的值。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    using namespace std;
     
    const int N = 210;
    const int INF = 0x3f3f3f3f;
    typedef long long ll;
    struct edge
    {
        int to, cap, next;
    }g[N*N*2];
    int head[N], iter[N], level[N];
    int n, m, cnt, _case = 0;
    void add_edge(int v, int u, int cap)
    {
        g[cnt].to = u, g[cnt].cap = cap, g[cnt].next = head[v], head[v] = cnt++;
        g[cnt].to = v, g[cnt].cap = 0, g[cnt].next = head[u], head[u] = cnt++;
    }
    bool bfs(int s, int t)
    {
        memset(level, -1, sizeof level);
        level[s] = 0;
        queue<int> que;
        que.push(s);
        while(! que.empty())
        {
            int v = que.front(); que.pop();
            for(int i = head[v]; i != -1; i = g[i].next)
            {
                int u = g[i].to;
                if(g[i].cap > 0 && level[u] < 0)
                {
                    level[u] = level[v] + 1;
                    que.push(u);
                }
            }
        }
        return level[t] == -1;
    }
    int dfs(int v, int t, int f)
    {
        if(v == t) return f;
        for(int &i = iter[v]; i != -1; i = g[i].next)
        {
            int u = g[i].to;
            if(g[i].cap > 0 && level[v] < level[u])
            {
                int d = dfs(u, t, min(g[i].cap, f));
                if(d > 0)
                {
                    g[i].cap -= d, g[i^1].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }
    int dinic(int s, int t)
    {
        int flow = 0, f;
        while(true)
        {
            if(bfs(s, t)) return flow;
            memcpy(iter, head, sizeof head);
            while(f = dfs(s, t, INF),f > 0)
                flow += f;
        }
    }
    int main()
    {
        int t;
        char ch[N];
        int d[N];
        scanf("%d", &t);
        while(t--)
        {
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= n; i++)
                scanf(" %c-%d", &ch[i], &d[i]);
            int l = 0, r = m, res = 0;
            while(l <= r)
            {
                cnt = 0;
                memset(head, -1, sizeof head);
                int mid = (l + r) >> 1;
                for(int i = 1; i <= n; i++) //石头拆点连边
                    if(ch[i] == 'S') add_edge(i, n + i, 1);
                    else add_edge(i, n + i, 2);
                for(int i = 1; i <= n; i++) //对于石头,连接源点和汇点
                {
                    if(abs(m - d[i]) <= mid)
                        add_edge(i + n, 2 * n + 1, 2);
                    if(abs(d[i] - 0) <= mid)
                        add_edge(0, i, 2);
                }
                if(m - 0 <= mid) add_edge(0, 2 * n + 1, 2); //源点和汇点连边
                for(int i = 1; i <= n; i++) //石头之间连边
                    for(int j = i + 1; j <= n; j++)
                        if(abs(d[i] - d[j]) <= mid)
                        {
                            add_edge(i + n, j, 2);
                            //add_edge(j + n, i, 2);
                        }
                if(dinic(0, 2 * n + 1) >= 2) r = mid - 1, res = mid;
                else l = mid + 1;
            }
            printf("Case %d: %d
    ", ++_case, l);
        }
        return 0;
    }

    B:LightOJ - 1167 Dangerous Tunnels:题意:从0--n+1,中间有一些路,走的时候起点必须大于终点,每条路都有一定的危险值,每一种方案需要挑选至少K条路,这些路里危险度最大的那条路就是整个方案的危险值,输出最小的危险值,如果没有方案的话输出no solutation! 二分枚举危险度,建图,然后跑一边拆点最大流,每条边容量为1,判断最大流结果是否大于等于k。

    #include<stdio.h>
    #include<queue>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    const int inf = ~0u >> 2;
    const int N = 215;
    const int M = 100000;
    struct eg {
    	int u, v, cap, cost;
    	eg() {}
    	eg(int a, int b, int c, int d) { u = a, v = b, cap = c, cost = d; }
    }edg[M];
    int fir[N], nex[M], ecnt;
    void add(int a, int b, int c, int d) {
    	edg[ecnt] = eg(a, b, c, d);
    	nex[ecnt] = fir[a], fir[a] = ecnt++;
    	edg[ecnt] = eg(b, a, 0, -d);
    	nex[ecnt] = fir[b], fir[b] = ecnt++;
    }
    int lev[N];
    bool Bfs(int s, int t, int up) {
    	queue<int>q;
    	memset(lev, -1, sizeof(lev));
    	lev[s] = 0; q.push(s);
    	while (!q.empty()) {
    		int u = q.front(); q.pop();
    		if (t == u) return 1;
    		for (int k = fir[u]; k != -1; k = nex[k]) {
    			if (edg[k].cost > up) continue;
    			int v = edg[k].v;
    			if (edg[k].cap && lev[v] == -1) {
    				lev[v] = lev[u] + 1;
    				q.push(v);
    			}
    		}
    	}
    	return 0;
    }
    int Dfs(int s, int t, int low, int up) {
    	if (s == t) return low;
    	int res = 0, a;
    	for (int k = fir[s]; k != -1; k = nex[k]) {
    		if (edg[k].cost > up) continue;
    		int v = edg[k].v;
    		if (edg[k].cap && lev[v] == lev[s] + 1) {
    			a = Dfs(v, t, min(low - res, edg[k].cap), up);
    			edg[k].cap -= a;
    			edg[k ^ 1].cap += a;
    			res += a;
    			if (res == low) return res;
    		}
    	}
    	if (res == 0) lev[s] = -1;
    	return res;
    }
    int Dinic(int s, int t, int up) {
    	int res = 0, minflow;
    	while (Bfs(s, t, up)) {
    		while (minflow = Dfs(s, t, inf, up)) res += minflow;
    	}
    	//printf("maxflow = %d
    ", res);
    	return res;
    }
    int solve(int s, int t, int up) {
    	int l = 0, r = inf, ans = -1;
    	while (l <= r) {
    		int mid = (l + r) >> 1;
    		if (Dinic(s, t, mid) >= up) r = mid - 1, ans = mid;
    		else l = mid + 1;
    		for (int i = 0; i < ecnt; i += 2) {
    			edg[i].cap += edg[i ^ 1].cap;
    			edg[i ^ 1].cap = 0;
    		}
    	}
    	return ans;
    }
    int main() {
    	int T, ca = 1;
    	scanf("%d", &T);
    	while (T--) {
    		memset(fir, -1, sizeof(fir)); ecnt = 0;
    		int n, m;
    		scanf("%d%d", &n, &m);
    		int s = 0, t1 = n + 1, t2 = 2 * n + 2;
    		for (int i = 1; i <= n; ++i) add(i, i + n + 1, 1, 0);
    		for (int i = 1; i <= m; ++i) {
    			int a, b, c;
    			scanf("%d%d%d", &a, &b, &c);
    			if (a > b) swap(a, b);
    			else if (a == b) continue;
    			if (a == 0) add(s, b, 1, c);
    			else add(a + n + 1, b, 1, c);
    		}
    		int k;
    		scanf("%d", &k);
    		add(t1, t2, k, 0);
    		int ans = solve(s, t2, k);
    		if (ans == -1) printf("Case %d: no solution
    ", ca++);
    		else printf("Case %d: %d
    ", ca++, ans);
    	}
    }

    C:LightOJ - 1176 Getting a T-shirt:题目大意:有m个人,衣服有n种颜色,(感觉这个地方有点绕,其实是有6个尺码,每个尺码有n种颜色的衣服,而题目又说了竞赛者不关心衣服颜色,所以意思就是每个尺码有n件衣服),给出每个参赛者想要的两种尺码,问能不能满足所有参赛者的要求。 考虑网络流,源点与每个人连一条容量为1的边,每个人与他想要的尺码连一条容量为1的边,这就限制了每个人只能选一件衣服的条件,对于每个尺码,与汇点连一条容量为n的边,表示每个尺码有n件跑一遍最大流,只要最后跑出的答案等于参赛者的人数就是满足,否则不满足。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #include<queue>
    using namespace std;
    const int maxn=1010;
    const int maxm=10010;
    const int inf=0x3f3f3f3f;
    struct Node
    {
        int to;
        int capa;
        int next;
    }edge[maxm];
    int source,sink;
    int cnt;
    int head[maxn];
    bool vis[maxn];
    int num[maxn];
    int dep[maxn];
    map<string,int> ma;
    void init()
    {
        memset(head,-1,sizeof(head));
        ma["XS"]=1;
        ma["S"]=2;
        ma["M"]=3;
        ma["L"]=4;
        ma["XL"]=5;
        ma["XXL"]=6;
        cnt=0;
        return;
    }
    void add(int u,int v,int capa)
    {
        edge[cnt].to=v;
        edge[cnt].capa=capa;
        edge[cnt].next=head[u];
        head[u]=cnt++;
        edge[cnt].to=u;
        edge[cnt].capa=0;
        edge[cnt].next=head[v];
        head[v]=cnt++;
        return;
    }
    bool bfs()
    {
        queue<int> que;
        que.push(source);
        memset(dep,-1,sizeof(dep));
        dep[source]=0;
        while(!que.empty())
        {
            int node=que.front();
            que.pop();
            for(int i=head[node];~i;i=edge[i].next)
            {
                int v=edge[i].to;
                if(edge[i].capa>0&&dep[v]==-1)
                {
                    dep[v]=dep[node]+1;
                    if(v==sink) return true;
                    que.push(v);
                }
            }
        }
        return dep[sink]!=-1;
    }
    int dfs(int node,int minn)
    {
        if(node==sink||minn==0)
        {
            return minn;
        }
        int r=0;
        for(int i=head[node];~i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(dep[v]==dep[node]+1&&edge[i].capa>0)
            {
                int tmp=dfs(v,min(edge[i].capa,minn));
                if(tmp>0)
                {
                    edge[i].capa-=tmp;
                    edge[i^1].capa+=tmp;
                    r+=tmp;
                    minn-=tmp;
                    if(!minn) break;
                }
            }
        }
        if(!r) dep[node]=-1;
        return r;
    }
    int dinic()
    {
        int maxflow=0;
        while(bfs())
        {
            maxflow+=dfs(source,inf);
        }
        return maxflow;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int test;
        scanf("%d",&test);
        for(int cas=1;cas<=test;cas++)
        {
            init();
            int n,m;
            scanf("%d%d",&n,&m);
            source=0;
            sink=m+10;
            for(int i=1;i<=m;i++)
            {
                string a,b;
                cin>>a>>b;
                add(source,i,1);
                add(i,ma[a]+m,1);
                add(i,ma[b]+m,1);
            }
            for(int i=1;i<=6;i++)
            {
                add(m+i,sink,n);
            }
            printf("Case %d: %s
    ",cas,dinic()==m?"YES":"NO");
        }
        return 0;
    }

    D:LightOJ - 1177 Angry Programmer:题意:一共有n台计算机,1号是发送端,n号是接受端你想让发送端与接受端之间无法通信,已经破坏每台电脑所需的费用(2--n-1),共有m条导线,每条线连接着两条电脑,并告诉你破坏这条线所需的费用,问你最少花费多少可以使得发送端与接受端之间无法通信。 思路:最小割的问题,因为最小割等于最大流,我们只需要求最大流即可。把计算机看成是顶点,由于顶点上有费用的限制,所以我们进行拆点,每个点到自身的流量为破坏这个电脑的费用,源点(1)和汇点(n)到自身的流量设为INF。 (这里由于流量的范围比较大,用Ford-Fulkerson算法可能会超时,这里我们改用Dinic算法,实际测试8ms就可过) 总结:拆点连边时容量不能为0,求最小割时不想让某条边选入最小割中,就置为极大值。

    #include<stdio.h>
    #include<string.h>
    #include<vector>
    #include<queue> 
    #define INF 1<<31-1
    #define min(x,y)(x<y?x:y)
    using namespace std;
    struct Edge
    {
    	int to;
    	int cap;
    	int rev;
    };
    vector<Edge>g[110];
    int p[51];
    int len[110];
    int pos[110];
    void add_edge(int from,int to,int cap)
    {
    	g[from].push_back((Edge){to,cap,g[to].size()});
    	g[to].push_back((Edge){from,0,g[from].size()-1});
    }
    bool bfs(int s,int t)
    {
    	memset(len,-1,sizeof(len));
    	queue<int>Q;
    	Q.push(s);
    	len[s]=0;
    	while(!Q.empty())
    	{
    		int u=Q.front();
    		Q.pop();
    		for(int i=0;i<g[u].size();i++)
    		{
    			Edge e=g[u][i];
    			int v=e.to;
    			if(e.cap>0&&len[v]==-1)
    			{
    				len[v]=len[u]+1;
    				Q.push(v);
    			}
    		}
    	}
    	if(len[t]==-1)
    		return false;
    	return true;
    }
    int dfs(int u,int t,int f)
    {
    	if(u==t)
    		return f;
    	for(int &i=pos[u];i<g[u].size();i++)
    	{
    		Edge &e=g[u][i];
    		int v=e.to;
    		if(e.cap>0&&len[u]==len[v]-1)
    		{
    			int d=dfs(v,t,min(e.cap,f));
    			if(d>0)
    			{
    				e.cap-=d;
    				g[v][e.rev].cap+=d;
    				return d;
    			}
    		}
    	}
    	return 0;
    }
    int max_flow(int s,int t)
    {
    	int res=0;
    	while(bfs(s,t))
    	{
    		memset(pos,0,sizeof(pos));
    		while(true)
    		{
    			int d=dfs(s,t,INF);
    		    if(d<=0)
    		    	break;
    			res+=d; 
    		}
    	}
    	return res;
    }
    int main()
    {
    	int c,n,m,i,from,to,cap,s,t,k=0;
    	scanf("%d",&c);
    	while(c--)
    	{
    		scanf("%d%d",&n,&m);
    		s=1;t=2*n;
    		for(i=s;i<=t;i++)
    			g[i].clear();
    		for(i=2;i<n;i++)
    			scanf("%d",&p[i]);
    		for(i=0;i<m;i++)
    		{
    			scanf("%d%d%d",&from,&to,&cap);
    			add_edge(from+n,to,cap);              //无向图双向都加边即可 
    			add_edge(to+n,from,cap);
    		}
    		for(i=2;i<n;i++)
    		{
    			add_edge(i,i+n,p[i]);
    		}
    		add_edge(s,s+n,INF);
    		add_edge(n,t,INF);
    		int res=max_flow(s,t);
    		printf("Case %d: %d
    ",++k,res);
    	}
    	return 0;
    } 

    E:LightOJ - 1405 The Great Escape:题目大意:给一个地图,地图上的*号表示人,人要逃出这个地图,'.'表示可以走的地方,每个人走的路径不能有重复的地方,问是否所有人都能逃出去。 对于每一个人,将它与源点连一条容量为1的边,对于每一个点,将其拆成两个点,连一条容量为1的边,表示只能走一次,对于那些在边界的点,将它与汇点相连,表示这个点可以出去,对于每一个点,将它与上下左右四个方向的点相连,表示能走。然后跑一遍最大流。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=2e4+100;
    const int maxm=2000010;
    const int inf=0x3f3f3f3f;
    struct Node
    {
        int to;
        int capa;
        int next;
    }edge[maxm];
    int n,m;
    int cnt;
    int nv;
    int source,sink;
    int head[maxn];
    char map[110][110];
    int dep[maxn];
    int dirx[]={0,1,0,-1};
    int diry[]={1,0,-1,0};
    void init()
    {
        memset(head,-1,sizeof(head));
        cnt=0;
        return;
    }
    void add(int u,int v,int capa)
    {
        edge[cnt].to=v;
        edge[cnt].capa=capa;
        edge[cnt].next=head[u];
        head[u]=cnt++;
        edge[cnt].to=u;
        edge[cnt].capa=0;
        edge[cnt].next=head[v];
        head[v]=cnt++;
        return;
    }
    bool bfs()
    {
        queue<int> que;
        que.push(source);
        memset(dep,-1,sizeof(dep));
        dep[source]=0;
        while(!que.empty())
        {
            int node=que.front();
            que.pop();
            for(int i=head[node];~i;i=edge[i].next)
            {
                int v=edge[i].to;
                if(edge[i].capa>0&&dep[v]==-1)
                {
                    dep[v]=dep[node]+1;
                    if(v==sink) return true;
                    que.push(v);
                }
            }
        }
        return dep[sink]!=-1;
    }
    int dfs(int node,int minn)
    {
        if(node==sink||minn==0)
        {
            return minn;
        }
        int r=0;
        for(int i=head[node];~i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(dep[v]==dep[node]+1&&edge[i].capa>0)
            {
                int tmp=dfs(v,min(edge[i].capa,minn));
                if(tmp>0)
                {
                    edge[i].capa-=tmp;
                    edge[i^1].capa+=tmp;
                    r+=tmp;
                    minn-=tmp;
                    if(!minn) break;
                }
            }
        }
        if(!r) dep[node]=-1;
        return r;
    }
    int dinic()
    {
        int maxflow=0;
        while(bfs())
        {
            maxflow+=dfs(source,inf);
        }
        return maxflow;
    }
    int getIndex(int x,int y)
    {
        return (x-1)*m+y;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int test;
        scanf("%d",&test);
        for(int cas=1;cas<=test;cas++)
        {
            init();
            scanf("%d%d",&n,&m);
            source=0;
            sink=n*m*2+10;
            getchar();
            for(int i=1;i<=n;i++)
            {
                scanf("%s",map[i]+1);
            }
            int sum=0;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=m;j++)
                {
                    if(i==1||i==n||j==1||j==m)
                    {
                        add(getIndex(i,j)+n*m,sink,1);
                    }
                    add(getIndex(i,j),getIndex(i,j)+n*m,1);
                    for(int k=0;k<4;k++)
                    {
                        int x=i+dirx[k];
                        int y=j+diry[k];
                        if(x>=1&&x<=n&&y>=1&&y<=m)
                        {
                            add(getIndex(i,j)+n*m,getIndex(x,y),1);
                        }
                    }
                    if(map[i][j]=='*')
                    {
                        sum++;
                        add(source,getIndex(i,j),1);
                    }
                }
            }
            if(dinic()==sum) printf("Case %d: yes
    ",cas);
            else printf("Case %d: no
    ",cas);
        }
        return 0;
    }

    F:LightOJ - 1071 Baker Vai:题目大意:给一个n*m的矩阵,有一个人在左上角,要走到右下角,再从右下角走回左上角,走到右下角的过程中只能走右边和下边,走回左上角只能走左边和上边,要求路径不能重复,矩阵的每个格子有一个值 ,每次走到这个格子就能得到这个值,要求这个值最大 刚开始想着走回左上角要怎么办,其实很简单,它等同于让我们去找另外一条走到右下角的路径,想到这里就很简单了,我们将每个点拆点,起点和终点拆的点相连的边容量为2,其他的为1,因为起点终点会经过两遍,而其他点只能经过一遍,费用为权值取负,然后跑一遍费用流,但是这样得出的答案并不是正确答案,因为起点和终点都走了两遍,所以要减去一次起点和终点的权值。最大费用流时容量置为负。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=20010;
    const int maxm=1e6+7;
    const int inf=0x3f3f3f3f;
    struct Node
    {
    	int to;
    	int capa;
    	int cost;
    	int next;
    }edge[maxm];
    int cnt;
    int n,m;
    int source,sink;
    int head[maxn];
    int map[110][110];
    int dis[maxn];
    bool vis[maxn];
    int pre[maxn];
    int rec[maxn];
    void init()
    {
    	cnt=0;
    	memset(head,-1,sizeof(head));
    	return;
    }
    void add(int u,int v,int capa,int cost)
    {
    	edge[cnt].to=v;
    	edge[cnt].capa=capa;
    	edge[cnt].cost=cost;
    	edge[cnt].next=head[u];
    	head[u]=cnt++;
    	edge[cnt].to=u;
    	edge[cnt].capa=0;
    	edge[cnt].cost=-cost;
    	edge[cnt].next=head[v];
    	head[v]=cnt++;
    	return;
    }
    int getIndex(int x,int y)
    {
    	return (x-1)*m+y;
    }
    bool spfa()
    {
    	queue<int> que;
    	que.push(source);
    	memset(dis,inf,sizeof(dis));
    	memset(vis,false,sizeof(vis));
    	memset(rec,-1,sizeof(rec));
    	memset(pre,-1,sizeof(pre));
    	dis[source]=0;
    	vis[source]=true;
    	while(!que.empty())
    	{
    		int node=que.front();
    		que.pop();
    		vis[node]=false;
    		for(int i=head[node];~i;i=edge[i].next)
    		{
    			int v=edge[i].to;
    			if(edge[i].capa>0&&dis[v]>dis[node]+edge[i].cost)
    			{
    				dis[v]=dis[node]+edge[i].cost;
    				rec[v]=i;
    				pre[v]=node;
    				if(!vis[v])
    				{
    					vis[v]=true;
    					que.push(v);
    				}
    			}
    		}
    	}
    	return dis[sink]!=inf;
    }
    int mcmf()
    {
    	int mincost=0;
    	while(spfa())
    	{
    		int node=sink;
    		int flow=inf;
    		while(node!=source)
    		{
    			flow=min(flow,edge[rec[node]].capa);
    			node=pre[node];
    		}
    		node=sink;
    		while(node!=source)
    		{
    			mincost+=flow*edge[rec[node]].cost;
    			edge[rec[node]].capa-=flow;
    			edge[rec[node]^1].capa+=flow;
    			node=pre[node];
    		}
    	}
    	return -mincost;
    }
    int main()
    {
    	//freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
    	int test;
    	scanf("%d",&test);
    	for(int cas=1;cas<=test;cas++)
    	{
    		init();
    		scanf("%d%d",&n,&m);
    		source=1;
    		sink=n*m*2;
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=1;j<=m;j++)
    			{
    				scanf("%d",&map[i][j]);
    			}
    		}
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=1;j<=m;j++)
    			{
    				int x=getIndex(i,j);
    				if((i==1&&j==1)||(i==n&&j==m))
    				{
    					add(x,x+n*m,2,-map[i][j]);
    				}
    				else
    				{
    					add(x,x+n*m,1,-map[i][j]);
    				}
    			}
    		}
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=1;j<=m;j++)
    			{
    				int x=getIndex(i,j);
    				int down=getIndex(i+1,j);
    				int right=getIndex(i,j+1);
    				if(i<n) add(x+n*m,down,1,0);
    				if(j<m) add(x+n*m,right,1,0);
    			}
    		}
    		printf("Case %d: %d
    ",cas,mcmf()-map[1][1]-map[n][m]);
    	}
    	return 0;
    }

    G:LightOJ - 1222 Gift Packing:题目大意:有n个礼物和n个盒子,每个盒子最多装一个礼物,每个礼物装进每个盒子都有不同的收益,问最大的收益 每个礼物和每个盒子建一个容量为1,费用为收益的负数的边,源点与每个礼物连一条容量为1,费用为0的边,每个盒子与汇点连一条容量为1,费用为0的边,跑一遍最小费用最大流即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #include<queue>
    using namespace std;
    const int maxn=1010;
    const int maxm=10010;
    const int inf=0x3f3f3f3f;
    struct Node
    {
        int to;
        int capa;
        int cost;
        int next;
    }edge[maxm];
    int source,sink;
    int cnt;
    int head[maxn];
    bool vis[maxn];
    int num[maxn];
    int dep[maxn];
    int pre[maxn];
    int rec[maxn];
    int dis[maxn];
    void init()
    {
        memset(head,-1,sizeof(head));
        memset(pre,-1,sizeof(pre));
        memset(rec,-1,sizeof(rec));
        cnt=0;
        return;
    }
    void add(int u,int v,int capa,int cost)
    {
        edge[cnt].to=v;
        edge[cnt].capa=capa;
        edge[cnt].cost=cost;
        edge[cnt].next=head[u];
        head[u]=cnt++;
        edge[cnt].to=u;
        edge[cnt].capa=0;
        edge[cnt].cost=-cost;
        edge[cnt].next=head[v];
        head[v]=cnt++;
        return;
    }
    bool spfa()
    {
        queue<int> que;
        que.push(source);
        memset(dis,inf,sizeof(dis));
        memset(vis,false,sizeof(vis));
        dis[source]=0;
        vis[source]=true;
        while(!que.empty())
        {
            int node=que.front();
            que.pop();
            vis[node]=false;
            for(int i=head[node];~i;i=edge[i].next)
            {
                int v=edge[i].to;
                if(edge[i].capa>0&&dis[v]>dis[node]+edge[i].cost)
                {
                    dis[v]=dis[node]+edge[i].cost;
                    rec[v]=i;
                    pre[v]=node;
                    if(!vis[v])
                    {
                        vis[v]=true;
                        que.push(v);
                    }
                }
            }
        }
        return dis[sink]!=inf;
    }
    int mcmf()
    {
        int maxflow=0;
        int mincost=0;
        while(spfa())
        {
            int node=sink;
            int flow=inf;
            while(node!=source)
            {
                flow=min(flow,edge[rec[node]].capa);
                node=pre[node];
            }
            node=sink;
            while(node!=source)
            {
                mincost+=flow*edge[rec[node]].cost;
                edge[rec[node]].capa-=flow;
                edge[rec[node]^1].capa+=flow;
                node=pre[node];
            }
        }
        return -mincost;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int test;
        scanf("%d",&test);
        for(int cas=1;cas<=test;cas++)
        {
            init();
            int n;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    int x;
                    scanf("%d",&x);
                    add(i,j+n,1,-x);
                }
            }
            source=0;
            sink=n*2+1;
            for(int i=1;i<=n;i++)
            {
                add(source,i,1,0);
            }
            for(int i=1;i<=n;i++)
            {
                add(i+n,sink,1,0);
            }
            printf("Case %d: %d
    ",cas,mcmf());
        }
        return 0;
    }

    H:LightOJ - 1237 Cyber Cafe:题目大意:有n个人去咖啡店,老板将他们的进入时间和走的时间都记录下来了,但是弄混了,对于每个人来说,老板要收的钱是他在咖啡店待的时间T减去一个给出的常数K的差的平方,而且老板最多只收G元,超过G元也算G元,问最少收益和最大收益分别是多少 n^2建图,对于一个进入时间,找出符合的走的时间,连一条容量为1,费用为差值的平方的边,所有的进入时间与源点连一条容量为1,费用为0的边,所有的走的时间与汇点连一条容量为1,费用为0的边,跑一遍费用流,这时候得到的是最少费用。然后再重新建一次图,不同的是这一次进入时间与走的时间连的边费用取负数,然后也跑一遍费用流。如何判断impossible的情况,如果跑完费用流最后的总流量不等于n,就impossible。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=510;
    const int maxm=100010;
    const int inf=0x3f3f3f3f;
    struct Node
    {
        int to;
        int capa;
        int cost;
        int next;
    }edge[maxm];
    int n,K,G;
    int source,sink;
    int cnt;
    int head[maxn];
    int dis[maxn];
    bool vis[maxn];
    int dep[maxn];
    int numa[maxn];
    int numb[maxn];
    int pre[maxn];
    int rec[maxn];
    void init()
    {
        memset(head,-1,sizeof(head));
        cnt=0;
        return;
    }
    void add(int u,int v,int capa,int cost)
    {
        edge[cnt].to=v;
        edge[cnt].capa=capa;
        edge[cnt].cost=cost;
        edge[cnt].next=head[u];
        head[u]=cnt++;
        edge[cnt].to=u;
        edge[cnt].capa=0;
        edge[cnt].cost=-cost;
        edge[cnt].next=head[v];
        head[v]=cnt++;
        return;
    }
    bool spfa()
    {
        memset(vis,false,sizeof(vis));
        memset(dis,inf,sizeof(dis));
        memset(rec,-1,sizeof(rec));
        memset(pre,-1,sizeof(pre));
        queue<int> que;
        que.push(source);
        dis[source]=0;
        vis[source]=true;
        while(!que.empty())
        {
            int node=que.front();
            que.pop();
            vis[node]=false;
            for(int i=head[node];~i;i=edge[i].next)
            {
                int v=edge[i].to;
                if(edge[i].capa>0&&dis[v]>dis[node]+edge[i].cost)
                {
                    dis[v]=dis[node]+edge[i].cost;
                    rec[v]=i;
                    pre[v]=node;
                    if(!vis[v])
                    {
                        vis[v]=true;
                        que.push(v);
                    }
                }
            }
        }
        return dis[sink]!=inf;
    }
    int mcmf()
    {
        int maxflow=0;
        int mincost=0;
        while(spfa())
        {
            int node=sink;
            int flow=inf;
            while(node!=source)
            {
                flow=min(flow,edge[rec[node]].capa);
                node=pre[node];
            }
            maxflow+=flow;
            node=sink;
            while(node!=source)
            {
                mincost+=flow*edge[rec[node]].cost;
                edge[rec[node]].capa-=flow;
                edge[rec[node]^1].capa+=flow;
                node=pre[node];
            }
        }
        if(maxflow!=n) return -1;
        return -mincost;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int test;
        scanf("%d",&test);
        for(int cas=1;cas<=test;cas++)
        {
            init();
            scanf("%d%d%d",&n,&K,&G);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&numa[i]);
            }
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&numb[i]);
            }
            source=0;
            sink=n*2+1;
            init();
            for(int i=1;i<=n;i++)
            {
                add(source,i,1,0);
                add(i+n,sink,1,0);
                for(int j=1;j<=n;j++)
                {
                    if(numb[j]>numa[i])
                    {
                        int cost=((numb[j]-numa[i])-K)*((numb[j]-numa[i])-K);
                        add(i,j+n,1,cost>G?G:cost);
                    }
                }
            }
            int min_ans=mcmf();
            init();
            for(int i=1;i<=n;i++)
            {
                add(source,i,1,0);
                add(i+n,sink,1,0);
                for(int j=1;j<=n;j++)
                {
                    if(numb[j]>numa[i])
                    {
                        int cost=((numb[j]-numa[i])-K)*((numb[j]-numa[i])-K);
                        add(i,j+n,1,cost>G?-G:-cost);
                    }
                }
            }
            int max_ans=mcmf();
            if(min_ans==-1||max_ans==-1)
            {
                printf("Case %d: impossible
    ",cas);
            }
            else
            {
                printf("Case %d: %d %d
    ",cas,-min_ans,max_ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    Python——str(字符串)内部功能介绍
    Python网络编程——设定并获取默认的套接字超时时间
    Python网络编程——主机字节序和网络字节序之间的相互转换
    Python网络编程——通过指定的端口和协议找到服务名
    python网络编程——将IPv4地址转换成不同的格式
    Python网络编程——获取远程设备的IP地址
    Python网络编程——设备名和IPv4地址
    Python+Flask+MysqL的web建设技术过程
    管理信息系统 第三部分 作业
    模型分离(选做)
  • 原文地址:https://www.cnblogs.com/shmilky/p/14089005.html
Copyright © 2011-2022 走看看