社区讨论

45pts 只能过 k<=3 求救

P7916 [CSP-S 2021] 交通规划参与者 8已保存回复 8

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
8 条
当前快照
1 份
快照标识符
@mhj0tccm
此快照首次捕获于
2025/11/03 18:52
4 个月前
此快照最后确认于
2025/11/03 18:52
4 个月前
查看原帖
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n, m, T, k;
int row[505][505], col[505][505], sta[250505], blo[250505], val[250505], bvl[250505], cnt;
int dis[28][250505], g[55][55], f[55][55];
bool vis[250055];
vector< pair<int, int> > G[505 * 505 + 50];
priority_queue< pair<int, int> > Q;
struct ex_node{//扩展:在边缘的节点 
	public:
		int d, p, c;
		friend istream & operator >> (istream &is, ex_node &qaq){
			is >> qaq.d >> qaq.p >> qaq.c;
			return is;
		}
};
vector<ex_node> ext;
int gid(int x, int y){//坐标转下标 
	return (x - 1) * (m - 1) + y;
}
void add(int u, int v, int c){//加边 
//	cerr << ">" << u << " " << v << " " << c << "\n";
	G[u].emplace_back(make_pair(v, c));
	G[v].emplace_back(make_pair(u, c));
}
void add(int x, int y, int xx, int yy, int c){//格点加边 
	int u = gid(x, y), v = gid(xx, yy);
	add(u, v, c);
}
void clr(){//多测清空 
	cnt = (n - 1) * (m - 1);
	memset(sta, -1, sizeof sta);
	memset(dis, 0x3f, sizeof dis);
	memset(f, 0x3f, sizeof f);
	memset(blo, 0, sizeof blo);
	memset(g, 0x3f, sizeof g);
	memset(val, 0, sizeof val);
	memset(bvl, 0, sizeof bvl);
	for (int i = 1; i <= n * m; i++)
		G[i].clear();
}
void dijkstra(int s){//跑最短路 
	memset(vis, 0, sizeof vis);
	int p = (s - (n - 1) * (m - 1) + 1) / 2;
	dis[p][s] = 0;
	Q.push({0, s});
	while (!Q.empty()){
		int u = Q.top().second;
	//	cerr << ":" << s << " " << p << " " << u << " " << dis[p][u] << "\n";
		Q.pop();
		if (vis[u])
			continue;
		vis[u] = 1;
		for (auto tmp : G[u]){
			int v = tmp.first, c = tmp.second;
			if (dis[p][v] > dis[p][u] + c){
				dis[p][v] = dis[p][u] + c;
				Q.push({-dis[p][v], v});
			}
		}
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin >> n >> m >> T;
	for (int i = 1; i < n; i++)
		for (int j = 1; j <= m; j++)
			cin >> col[i][j];
	for (int i = 1; i <= n; i++)
		for (int j = 1; j < m; j++)
			cin >> row[i][j];
	while (T--){
		cin >> k;
		clr();
		bool ovo = 1, owo = 0;
		for (int i = 1; i <= k; i++){
			ex_node awa;
			cin >> awa;
			ext.emplace_back(awa);
			ovo &= awa.c;
			owo |= awa.c;
			sta[awa.p] = awa.c;
			val[awa.p] = awa.d;
		}
		if (ovo == owo){//所有附加点同色 
			cout << "0\n";
			continue;
		}
		for (int i = 1; i < n - 1; i++)
			for (int j = 1; j < m; j++)
				add(i, j, i + 1, j, row[i + 1][j]);
		for (int i = 1; i < n; i++)
			for (int j = 1; j < m - 1; j++)
				add(i, j, i, j + 1, col[i][j + 1]);//建网格内部在对偶图上对应的边 
		int lst = -1;
		for (int i = 1; i <= (n + m << 1); i++){//找外圈的块 
			if (sta[i] == -1)
				blo[i] = cnt;
			else if (lst = -1 || sta[i] ^ lst == 1){
				blo[i] = ++cnt;
				lst = sta[i];
				bvl[cnt] = val[i];
			}else
				blo[i] = cnt;
		}
		for (int i = 1; i <= (n + m << 1); i++){//找外圈的块 
			if (sta[i] == -1)
				blo[i] = cnt;
			else
				break;
		}
	//	cerr << cnt << "\n";
		for (int i = (n - 1) * (m - 1) + 1; i < cnt; i++)
			add(i, i + 1, bvl[i]);
		add(cnt, (n - 1) * (m - 1) + 1, bvl[cnt]);
	//	cerr << "qwq\n";
		for (int i = 1; i < m; i++)//边缘的点建边 
			add(blo[i], gid(1, i), row[1][i]);
		for (int i = m + 1; i < m + n; i++)
			add(blo[i], gid(i - m, m - 1), col[i - m][m]);
	//	cerr << "qwq\n";
		for (int i = m + n + 1;  i < (m << 1) + n; i++)
			add(blo[i], gid(n - 1, m - (i - m - n)), row[n][m - (i - m - n)]);
		for (int i = (m << 1) + n + 1; i < (m + n << 1); i++)
			add(blo[i], gid(n - (i - (m << 1) - n), 1), col[n - (i - (m << 1) - n)][1]);
		for (int i = (n - 1) * (m - 1) + 1; i <= cnt; i += 2)
			dijkstra(i);
		for (int i = (n - 1) * (m - 1) + 1; i <= cnt; i += 2)//取出每一块的最短路 
			for (int j = (n - 1) * (m - 1) + 1; j <= cnt; j++){
				int p = (i - (n - 1) * (m - 1) + 1) / 2;
			//	cerr << i << " " << j << " " << " " << p << "\n";
				g[i - (n - 1) * (m - 1)][j - (n - 1) * (m - 1)] = dis[p][j];
				g[j - (n - 1) * (m - 1)][i - (n - 1) * (m - 1)] = dis[p][j];
			}
		int ccnt = cnt - (n - 1) * (m - 1);
		for (int len = 1; len <= ccnt; len++){//区间 dp 合并 
			for (int i = 1; i + len - 1 <= ccnt; i++){
				int j = i + len - 1;
			//	cerr << i << " " << j << " "; 
				if (len == 1)
					f[i][j] = 0;
				else if (len == 2)
					f[i][j] = g[i][j];
				for (int k = i + 1; k < j; k++)
					f[i][j] = min(f[i][j], f[i][k - 1] + g[i][k] + f[k + 1][j]);
			//	cerr << g[i][j] << "\n";
			}
		}
		cout << f[1][ccnt] << "\n";
	}
	return 0;
}

回复

8 条回复,欢迎继续交流。

正在加载回复...