ACM-ICPC 2018 沈阳赛区网络预赛 F题 Fantastic Graph(上下界网络流)

版权声明:Amove? https://blog.csdn.net/Amovement/article/details/82914725

                                                    Fantastic Graph

"Oh, There is a bipartite graph.""Make it Fantastic."

X wants to check whether a bipartite graph is a fantastic graph. He has two fantastic numbers, and he wants to let all the degrees to between the two boundaries. You can pick up several edges from the current graph and try to make the degrees of every point to between the two boundaries. If you pick one edge, the degrees of two end points will both increase by one. Can you help X to check whether it is possible to fix the graph?

Input

There are at most 3030 test cases.

For each test case,The first line contains three integers NN the number of left part graph vertices, MM the number of right part graph vertices, and KK the number of edges ( 1 \le N \le 20001≤N≤2000,0 \le M \le 20000≤M≤2000,0 \le K \le 60000≤K≤6000 ). Vertices are numbered from 11to NN.

The second line contains two numbers L, RL,R (0 \le L \le R \le 300)(0≤L≤R≤300). The two fantastic numbers.

Then KK lines follows, each line containing two numbers UU, VV (1 \le U \le N,1 \le V \le M)(1≤U≤N,1≤V≤M). It shows that there is a directed edge from UU-th spot to VV-th spot.

Note. There may be multiple edges between two vertices.

Output

One line containing a sentence. Begin with the case number. If it is possible to pick some edges to make the graph fantastic, output "Yes"(without quote), else output "No" (without quote).

样例输入复制

3 3 7
2 3
1 2
2 3
1 3
3 2
3 3
2 1
2 1
3 3 7
3 4
1 2
2 3
1 3
3 2
3 3
2 1
2 1

样例输出复制

Case 1: Yes
Case 2: No

题目来源

ACM-ICPC 2018 沈阳赛区网络预赛

 

一、原题地址

点我传送

 

二、大致题意

左边和右边分别有n、m个点,然后有k条边将他们连接起来。询问删掉一些边是否能使所有点的度数在区间[L,R]内。

 

三、思路

现场学习上下限网络流。

 

四、代码

#include <vector>
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <cstring>
#include <queue>
#include <list>
#include <cstdio>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <cctype>
#include <sstream>
#include <iterator>
#include <functional>
#include <stdlib.h>
#include <time.h>
#include <bitset>
using namespace std;
const int inf = 0x3f3f3f3f;

int n, m, k;
int L, R;
const int maxn = 6005;
struct Edge
{
	Edge() {}
	Edge(int from, int to, int cap, int flow) :from(from), to(to), cap(cap), flow(flow) {}
	int from, to, cap, flow;
};

struct Dinic
{
	int n, m, s, t;            //结点数,边数(包括反向弧),源点与汇点编号
	vector<Edge> edges;     //边表 edges[e]和edges[e^1]互为反向弧
	vector<int> G[maxn];    //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
	bool vis[maxn];         //BFS使用,标记一个节点是否被遍历过
	int d[maxn];            //从起点到i点的距离
	int cur[maxn];          //当前弧下标

	void init(int n,int s,int t)
	{
		this->n = n;
		this->s = s, this->t = t;
		for (int i = 0; i <= n; i++) G[i].clear();
		edges.clear();
	}

	void AddEdge(int from, int to, int cap)
	{
		edges.push_back(Edge(from, to, cap, 0));
		edges.push_back(Edge(to, from, 0, 0));
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}

	bool BFS()
	{
		memset(vis, 0, sizeof(vis));
		queue<int> Q;//用来保存节点编号的
		Q.push(s);
		d[s] = 0;
		vis[s] = true;
		while (!Q.empty())
		{
			int x = Q.front(); Q.pop();
			for (int i = 0; i<G[x].size(); i++)
			{
				Edge& e = edges[G[x][i]];
				if (!vis[e.to] && e.cap>e.flow)
				{
					vis[e.to] = true;
					d[e.to] = d[x] + 1;
					Q.push(e.to);
				}
			}
		}
		return vis[t];
	}

	int DFS(int x, int a)
	{
		if (x == t || a == 0)return a;
		int flow = 0, f;//flow用来记录从x到t的最小残量
		for (int& i = cur[x]; i<G[x].size(); i++)
		{
			Edge& e = edges[G[x][i]];
			if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
			{
				e.flow += f;
				edges[G[x][i] ^ 1].flow -= f;
				flow += f;
				a -= f;
				if (a == 0) break;
			}
		}
		return flow;
	}

	int Maxflow()
	{
		int flow = 0;
		while (BFS())
		{
			memset(cur, 0, sizeof(cur));
			flow += DFS(s, inf);
		}
		return flow;
	}
}DC;
void build()
{
	scanf("%d %d", &L, &R);
	DC.init(4004, 4002, 4001);
	for (int i = 1; i <= k; i++)
	{
		int u, v;
		scanf("%d %d", &u, &v);
		DC.AddEdge(u, v + n, 1);
	}
	int s = 4003, t = 4004, ss = 4001, tt = 4002;
	for (int i = 1; i <= n; i++)
	{
		DC.AddEdge(s, i, R - L);
		DC.AddEdge(s, ss, L);
		DC.AddEdge(tt, i, L);
	}
	for (int i = n + 1; i <= n + m; i++)
	{
		DC.AddEdge(i, t, R - L);
		DC.AddEdge(i, ss, L);
		DC.AddEdge(tt, t, L);
	}
	DC.AddEdge(t, s, inf);
}

int main()
{
	int K = 1;
	while (scanf("%d %d %d", &n, &m, &k) != EOF)
	{
		build();
		DC.Maxflow();
		int flag = 1;
		for (int i = 0; i<DC.G[4002].size(); i++) 
		{
			Edge e = DC.edges[DC.G[4002][i]];			
			if(e.cap!=e.flow)			
			{				
				flag=0;				
				break;			
			}		
		}	
		printf("Case %d: ", K++);
		if (flag)
			printf("Yes\n");
		else printf("No\n");

	}
}

 

展开阅读全文

没有更多推荐了,返回首页