题目笔记——双网通行
题目大意
给定一个 \(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\)):
- 与 \(u\) 直接连边。
- 与 \(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;
}

浙公网安备 33010602011771号