题目笔记——双网通行

题目大意

给定一个 \(n\) 个点,\(m\) 条边的图,有以下操作:

  • 从此时所在的点到达周围与其直接连边的点,消耗代价 \(1\)。
  • 从此时所在的点到达与此点颜色相同的点,消耗代价 \(1\)(只有 \(0\) 和 \(1\) 两种颜色)。

再给定 \(1\) 到 \(u\) 所有点的颜色,求每个点到达其他所有点所花代价之和,即求对于每个 \(1\le u\le n\),求 \(\sum\limits_{v=1}^nD(u,v)\)。其中 \(D(u,v)\) 计为从 \(u\) 到 \(v\) 的最少代价。(下面都将用 \(u\) 来表示)

解题思路

此题为诈骗题,并不需要求最短路。

首先,有两种点已知距离 \(u\) 为 \(1\)(即每个点所花代价为 \(1\)):

  1. 与 \(u\) 直接连边。
  2. 与 \(u\) 颜色相同。

接下来就要进行分类讨论:

如果 \(u\) 周围有与 \(u\) 颜色不同的点

那么所有与 \(u\) 颜色不同的点都可以通过从 \(u\) 到周围与 \(u\) 颜色不同的点再到所有点(除了直接与 \(u\) 相连接),每个点所花代价为 \(2\)。

如果 \(u\) 周围都是与 \(u\) 颜色相同的点

由此,可以发现:与 \(u\) 颜色不同但周围有与 \(u\) 颜色相同的点可以从 \(u\) 到该点周围再到该点,每个点所花代价为 \(2\)。

与 \(u\) 颜色不同且周围没有与 \(u\) 颜色相同的点就只能从与 \(u\) 颜色不同但周围有与 \(u\) 颜色相同的点到达,所以每个点所花代价为 \(3\)。

分类讨论,求出每种情况的个数,计算就行了。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 20;
int c, t, n, m, cnt, a[20][20], f[N][20];
string s[N];

signed main(){
//	freopen("sheet.in", "r", stdin);
//	freopen("sheet.out", "w", stdout);
	cin >> c >> t;
	while(t --){
		cnt = 0;
		memset(a, 0, sizeof(a));
		memset(f, 0, sizeof(f));
		cin >> n >> m;
		for(int i = 1; i <= n; i++){
			cin >> s[i];
			for(int j = 0; j < m; j++){
				if(s[i][j] == '1') cnt ++;
			}
		}
		for(int i = 1; i <= n; i++){
			for(int j = 0; j < m; j++){
				for(int k = j + 1; k < m; k++){
					if(s[i][j] == '1' && s[i][k] == '1'){
						a[j][k] ++;
						a[k][j] = a[j][k];
					}
				}
			}
		}
		f[1][0] = 0;
		for(int i = 0; i < (1 << m); i++){
			for(int j = 0; j < m; j++){
				if(!(i & (1ll << j))) continue;
				for(int k = 0; k < m; k++){
					if(!(i & (1ll << k)) || j == k) continue;
					f[i][j] = max(f[i][j], f[i ^ (1 << j)][k] + a[j][k]);
				}
			}
		}
		int mx = 0;
		for(int i = 0; i < m; i++) mx = max(mx, f[(1 << m) - 1][i]);
		cout << cnt - mx << endl;
	}
	return 0;
}
posted @ 2026-10-27 16:32  show__code  阅读(7)  评论(0)    收藏  举报