SGU 185 Two shortest 网络流+spfa+省内存

1 篇文章 0 订阅
1 篇文章 0 订阅

题意:

给一个无向图,问从1号点到N号点是否存在两条或以上没有公共边的最短路,如果存在输出路径,否则输出无解。


思路:

先求一次最短路,那么对于dis[j]=dis[i]+w[i][j] 的边w[i][j] 则一定在最短路上,那么在网络上建边i->j,流量为1,如果最后最大流大于等于2即满足题意,然后找有流的边dfs找解即可。要注意的是这道题的内存限制是4096KB,在大内存的时代,这么严格的内存要求已经很少见了。。。用的是GZ大牛的Dinic,要比一般的dinic多一个数组,各种MLE,后来改了spfa的写法后终于过了。



贴上挫代码一份:

#include<cstdio>
#include<string>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;

const int maxnode = 401 + 5;
const int maxedge = 401 * 401 * 2 + 10;
const int oo = 100000000;
struct Dinic
{
	int node, src, dest, nedge;
	int head[maxnode], next[maxedge];
	short point[maxedge];
	short flow[maxedge], capa[maxedge];
	short dist[maxnode], Q[maxnode];
	int  work[maxnode];

	vector<short>path[2];
	int sum;

	void init (int _node, int _src, int _dest)
	{
		path[0].clear();
		path[1].clear();
		node = _node;
		src = _src;
		dest = _dest;
		for (int i = 0; i < node; i++) head[i] = -1;
		nedge = 0;
	}
	void addedge (short u, short v, short c1, short c2)
	{
		point[nedge] = v, capa[nedge] = c1, flow[nedge] = 0, next[nedge] = head[u], head[u] = (nedge++);
		point[nedge] = u, capa[nedge] = c2, flow[nedge] = 0, next[nedge] = head[v], head[v] = (nedge++);
	}
	bool dinic_bfs()
	{
		memset (dist, -1, sizeof (dist) );
		dist[src] = 0;
		int sizeQ = 0;
		Q[sizeQ++] = src;
		for (int cl = 0; cl < sizeQ; cl++)
			for (int k = Q[cl], i = head[k]; i >= 0; i = next[i])
				if (flow[i] < capa[i] && dist[point[i]] < 0)
				{
					dist[point[i]] = dist[k] + 1;
					Q[sizeQ++] = point[i];
				}
		return dist[dest] >= 0;
	}
	int dinic_dfs (int x, int exp)
	{
		if (x == dest) return exp;
		for (int &i = work[x]; i >= 0; i = next[i])
		{
			short v = point[i], tmp;
			if (flow[i] < capa[i] && dist[v] == dist[x] + 1 && (tmp = dinic_dfs (v, min (exp, capa[i] - flow[i]) ) ) > 0)
			{
				flow[i] += tmp;
				flow[i ^ 1] -= tmp;
				return tmp;
			}
		}
		return 0;
	}
	int dinic_flow()
	{
		int result = 0;
		while (dinic_bfs() )
		{
			for (int i = 0; i < node; i++) work[i] = head[i];
			while (1)
			{
				int delta = dinic_dfs (src, oo);
				if (delta == 0) break;
				result += delta;
			}
		}
		return result;
	}

	void path_dfs (int x)
	{
		if (x == dest) return;
		path[sum].push_back (x);
		for (int i = head[x]; i >= 0; i = next[i])
		{
			//printf("^^^%d %d %d\n",x,point[i],flow[i]);
			if (flow[i] >= 1)
			{
				flow[i] = 0;
				path_dfs (point[i]);
				break;
			}
		}
	}


	void get_res()
	{
		//printf("@@@%d\n",dest);
		sum = 0;
		for (int i = head[1]; i >= 0; i = next[i])
		{
			if (flow[i] >= 1)
			{
				path[sum].push_back (1);
				path_dfs (point[i]);
				sum++;
			}
			if (sum >= 2) break;
		}
	}

	void output()
	{
		// printf ("@@@%d %d %d\n", (int) path[0].size(),(int) path[1].size() ,sum);
		printf ("%d", path[0][0]);
		for (int i = 1; i < (int) path[0].size() ; i++)
		{
			printf (" %d", path[0][i]);
		}
		printf ("\n");
		printf ("%d", path[1][0]);
		for (int i = 1; i < (int) path[1].size() ; i++)
		{
			printf (" %d", path[1][i]);
		}
		printf ("\n");
	}

	void show()
	{
		for (int k = 0; k <= dest; k++)
		{
			for (int i = head[k]; i >= 0; i = next[i])
			{
				printf ("$$$%d %d %d\n", k, point[i], flow[i]);
			}
		}
	}

} Solver;
//
//
//#define INF 100000000
//void spfa (int n, int s)      //这种spfa的写法容易超内存
//{
//	for (int i = 1; i <= n; ++i)
//		d[i] = INF;
//	memset (mark, false , sizeof (mark) );
//	d[s] = 0;
//	while (Q.size() ) Q.pop();
//	Q.push (s);
//	mark[s] = true;
//	while (Q.size() )
//	{
//		int k = Q.front();
//		Q.pop();
//		mark[k] = false;
//		for (int i = 0; i < adj[k].size(); ++i, ++i)
//		{
//			int s = adj[k][i];
//			int w = adj[k][i + 1];
//			if (d[k] + w < d[s])
//			{
//				d[s] = d[k] + w;
//				if (mark[s] == 0)
//				{
//					mark[s] = true;
//					Q.push (s);
//				}
//			}
//		}
//	}
//	return;
//}

int N, M, x, y, l;


#define INF 10000000
#define MAX 401
#define LMT 401
int dis[MAX];
bool vis[MAX];
short g[MAX][MAX];
short q[MAX];

int spfa (short s, short t)
{
	short i, j, head, tail;
	head = tail = 0;
	memset (vis, 0, sizeof (vis) );
	for (i = 1; i <= N; i++) dis[i] = INF;
	dis[s] = 0;
	vis[s] = true;
	q[tail++] = s;
	while (head != tail)
	{
		i = q[head];
		head = (head + 1) % LMT;
		vis[i] = 0;
		for (j = 1; j <= N; j++)
			if (g[i][j] != -1 && dis[j] > dis[i] + g[i][j])
			{
				dis[j] = dis[i] + g[i][j];
				if (0 == vis[j])
				{
					vis[j] = 1;
					q[tail] = j;
					tail = (tail + 1) % LMT;
				}
			}
	}
	return dis[t] < INF;
}



int main()
{
#ifdef untitled1
	freopen ("in.in", "r", stdin);
#endif // untitled1
	scanf ("%d%d", &N, &M);
	memset (g, -1, sizeof (g) );
	for (int i = 1; i <= M; i++)
	{
		scanf ("%d%d%d", &x, &y, &l);
//		adj[x].push_back ( (short) y);
//		adj[x].push_back ( (short) l);
//		adj[y].push_back ( (short) x);
//		adj[y].push_back ( (short) l);
		g[x][y] = (short) l;
		g[y][x] = (short) l;
	}
	spfa (1, N);
	Solver.init (N + 2, 0, N + 1);
	Solver.addedge (0, 1, 2, 0);
	Solver.addedge (N, N + 1, 2, 0);
	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= N; j++)
		{
			if (g[i][j] != -1 && dis[j] == dis[i] + g[i][j])
			{
				Solver.addedge (i, j, 1, 0);
			}
		}
	}

	int res = Solver.dinic_flow();
	//Solver.show();
	//printf ("~~~%d\n", res);
	if (res >= 2)
	{
		Solver.get_res();
		Solver.output();
	}
	else
	{
		printf ("No solution\n");
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值