UVA 1161 航程规划

发现自己是所有提交里跑的最快的,于是说一下自己的建模方式。

不要向其他题解那样每条航线拆成两个点,而是每条航线是一个点,用 vector<flight>arr[i] 存一下以 i 号城市为起点的所有航线,( flight 是自己定义的结构体,存终点、出发时间、到达时间、乘客上限),对每个 arr[i] 内部排个序(出发早的航线在前),一个 arr[i] 内部的每个航线和后一个航线连一条无限容量的边,表示可以在这个起始城市呆多久都行。

对于每个航线 t ,去终点对应的 arr[i] 里找第一个符合要求的航线(换乘来得及的),连一条容量为航线 t 乘客上限的边即可。

最后别忘了源点和汇点,很容易处理,不细讲了。

和其他题解相比,好处是点数减半,边数减了很多很多。所以快。

//#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<vector>
#include<string.h>
#include<queue>
#include<assert.h>
#include<stack>
#include<map>
using namespace std;
const int maxn = 1e4+ 5;
const int INF = 1e8;
struct edge
{
	int from, to, cap, flow;
};
struct dinic
{
	int d[maxn];
	int vis[maxn];
	int s, t;
	int cur[maxn];
	vector<int> G[maxn];
	vector<edge> edges;

	void init()
	{
		edges.clear();
		for (int i = 0; i < maxn; i++)G[i].clear();
	}

	void add_edge(int from,int to,int c)
	{
		edges.push_back(edge{ from,to,c,0 });
		edges.push_back(edge{ to,from,0,0 });
		int m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}

	bool bfs()
	{
		d[s] = 0;
		memset(vis, 0, sizeof(vis));
		vis[s] = 1;
		queue<int> q; q.push(s);

		while (!q.empty())
		{
			int x = q.front(); q.pop();
			for (int i = 0; i < G[x].size(); i++)
			{
				edge& e = edges[G[x][i]];
				int v = e.to;
				if (!vis[v] && e.cap > e.flow)
				{
					vis[v] = 1;
					d[v] = d[x] + 1;
					q.push(v);
				}
			}
		}
		return vis[t];
	}

	int dfs(int u, int a)
	{
		if (u == t || a == 0)return a;
		int flow = 0, f;
		for (int& i = cur[u]; i < G[u].size(); i++)
		{
			edge& e = edges[G[u][i]];
			int v = e.to;
			if (d[v] == d[u] + 1 && (f = dfs(v, min(a, e.cap - e.flow))) > 0)
			{
				flow += f;
				a -= f;
				edges[G[u][i]].flow += f;
				edges[G[u][i]^1].flow -= f;
				if (a == 0)return flow;
			}
		}
		return flow;
	}

	int maxflow(int s, int t)
	{
		this->s = s; this->t = t;
		int flow = 0;
		while (bfs())
		{
			memset(cur, 0, sizeof(cur));
			flow += dfs(s, INF);
		}
		return flow;
	}
}di;
int n,m;
map<string, int> dict;
string arr[155];
int tt;
struct flight
{
	int t1, t2;
	int num;
	int dest;
	int id;
	bool operator < (const flight& t)const
	{
		return t1 < t.t1;
	}
};
vector<flight> city[155];
int cnt;
int hhmm2t(int x)
{
	int h = x / 100;
	int m = x % 100;
	return h * 60 + m;
}
void init()
{
	dict.clear(); di.init();
	cnt = 2;
	for (int i = 0; i < 155; i++)city[i].clear();
	string str;
	cin >> str; arr[1] = str; dict[str] = 1;
	cin >> str; arr[2] = str; dict[str] = 2;
	cin >> tt; tt = hhmm2t(tt);
	cin >> m;
	for (int i = 0; i < m; i++)
	{
		string a, b;
		int num, t1, t2;
		cin >> a >> b >> num >> t1 >> t2;
		t1 = hhmm2t(t1); t2 = hhmm2t(t2);
		if (!dict.count(a))
		{
			cnt++;
			dict[a] = cnt;
			arr[cnt] = a;
		}
		if (!dict.count(b))
		{
			cnt++;
			dict[b] = cnt;
			arr[cnt] = b;
		}
		int start = dict[a];
		int dest = dict[b];
		if (start == 2)continue;
		city[start].push_back(flight{ t1,t2,num,dest,-1 });
	}
	assert(cnt == n);
	for (int i = 1; i <= cnt; i++)
	{
		sort(city[i].begin(), city[i].end());
	}
	int sz = 0;
	for (int i = 1; i <= cnt; i++)
	{
		for (int g = 0; g < city[i].size(); g++)
		{
			flight& f = city[i][g];
			sz++;
			f.id = sz;
		}
	}
	int T = sz + 1;
	for (int i = 1; i <= cnt; i++)
	{
		for (int g = 0; g+1 < city[i].size(); g++)
		{
			flight& f = city[i][g];
			di.add_edge(f.id, f.id + 1, INF);
		}
	}
	for (int i = 1; i <= cnt; i++)
	{
		for (int g = 0; g < city[i].size(); g++)
		{
			flight& f = city[i][g];
			int de = f.dest;
			if (de == 2&&f.t2<=tt)              //
			{
				di.add_edge(f.id, T, f.num);
			}
			else
			{
				for (int j = 0; j < city[de].size(); j++)
				{
					if (f.t2 + 30 <= city[de][j].t1)
					{
						di.add_edge(f.id, city[de][j].id, f.num);
						break;
					}
				}
			}
		}
	}
	di.add_edge(0, 1, INF);
	cout<<di.maxflow(0,T)<<endl;
}
int main()
{
	while (cin >> n)
	{
		init();
	}
}

 

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值