P2747 [USACO5.4]周游加拿大Canada Tour DP

1030考试T4

​ 题目大意:

​ 小 R 赢得了一张 L 国家环游机票。旅行在这家航空公司开放的最西边的城市开始,然后一直自西向东旅行,直到你到达最东边的城市,再由东向西返回,直到你回到开始的城市。除了旅行开始的城市之外,每个城市只能访问一次,因为开始的城市必定要被访问两次(在旅行的开始和结束)。当然不允许使用其他公司的航线或者用其他的交通工具。给出这个航空公司开放的城市的列表,和两两城市之间的直达航线列表。找出能够访问尽可能多的城市的路线,这条路线必须满足上述条件,也就是从列表中的第一个城市开始旅行,访问到列表中最后一个城市之后再返回第一个城市。

题目链接

​ DP.

​ 题目让你找一条从\(n\)到1.再从1到\(n\)并且不重复经过点的最长路径.从\(n\)到1的路径可以看做是从1到\(n\)的另一条路径,所以我们可以设:

\(f[i][j]\)表示第一条路径走到\(i\),第二条路径走到\(j\)的最长路径,所以最后的答案应该是\(max(f[i][n])\).保证\(i,n\)联通.

​ 然后转移:\(f[i][j] = f[i][k] + 1\),保证\(k, j\)联通,也就是\(f[i][k]\)有值.因为着两条路径可以交换,所以\(f[j][i] = f[i][j]\).强制\(j > i, j > k\)是为了防止重复经过一个点.

#include <bits/stdc++.h>

using namespace std;

const int N = 505, M = 3005;
int n, m, ans;
string a, b;
int vis[N][N], f[N][N];
map <string, int> mp;

int main() {
	
	cin >> n >> m;
	for(int i = 1;i <= n; i++) {
		cin >> a; mp[a] = i;
	}
	for(int i = 1;i <= m; i++) {
		cin >> a >> b;
		vis[mp[a]][mp[b]] = vis[mp[b]][mp[a]] = 1;
	}
	
	memset(f, -63, sizeof(f)); f[1][1] = 1;
	for(int i = 1;i <= n; i++) 
		for(int j = i + 1;j <= n; j++) 
			for(int k = 1;k < j; k++) 
				if(vis[j][k])
					f[i][j] = f[j][i] = max(f[i][j], f[i][k] + 1);
	ans = 1;
	for(int i = 1;i <= n; i++)
		if(vis[i][n]) ans = max(ans, f[i][n]);
	printf("%d", ans);

	return 0;
}
posted @ 2020-11-02 06:28  C锥  阅读(63)  评论(0编辑  收藏  举报