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;
    }
  • 相关阅读:
    Zend Framework 2.1.5 中根据服务器的环境配置调用数据库等的不同配置
    在基于 Eclipse 的 IDE 中安装和使用 Emmet(ZenCoding)
    【翻译】Emmet(Zen Coding)官方文档 之六 自定义 Emmet
    【翻译】Emmet(Zen Coding)官方文档 之二 缩写
    【翻译】Emmet(Zen Coding)官方文档 之七 一览表
    【翻译】Emmet(Zen Coding)官方文档 之三 CSS 缩写
    【翻译】Emmet(Zen Coding)官方文档 之四 动作
    【翻译】Emmet(Zen Coding)官方文档 之一 web 编程的必备工具
    Zend Framework 2 时区设置警告问题的解决
    【翻译】Emmet (Zen Coding) 元素类型
  • 原文地址:https://www.cnblogs.com/shmilky/p/14089005.html
Copyright © 2011-2022 走看看