省选模拟赛 cti
3 cti (cti.cpp/in/out, 1s, 512MB)
3.1 Description
有一个 n × m 的地图, 地图上的每一个位置可以是空地, 炮塔或是敌人. 你需要操纵炮塔消灭
敌人.
对于每个炮塔都有一个它可以瞄准的方向, 你需要在它的瞄准方向上确定一个它的攻击位置,
当然也可以不进行攻击. 一旦一个位置被攻击, 则在这个位置上的所有敌人都会被消灭.
保证对于任意一个炮塔, 它所有可能的攻击位置上不存在另外一个炮塔.
定义炮弹的运行轨迹为炮弹的起点和终点覆盖的区域. 你需要求出一种方案, 使得没有两条炮
弹轨迹相交.
3.2 Input Format
第一行两个整数 n,m.
接下来 n 行, 每行 m 个整数, 0 表示空地, −1,−2,−3,−4 分别表示瞄准上下左右的炮塔, 正整
数 p 表示表示此位置有 p 个敌人.
3.3 Output Format
一行一个整数表示答案.
3.4 Sample 1
3.4.1 Input
3 2
0 9
-4 3
0 -1
3.4.2 Output
9
3.5 Sample 2
3.5.1 Input
4 5
0 0 -2 0 0
-4 0 5 4 0
0 -4 3 0 6
9 0 0 -1 0
3.5.2 Output
12
3.6 Constraints
对于前 20% 的数据, n,m ≤ 5;
对于另 20% 的数据, 朝向上下的炮塔至多有 2 个;
对于另 20% 的数据, 至多有 6 个炮塔;
对于 100% 的数据, 1 ≤ n,m ≤ 50, 每个位置的敌人数量 < 1000.
分析:将题目看作炮塔和敌人“匹配”,就和比特板这道题几乎一模一样了.
需要注意的是炮塔可以不攻击任何敌人,那么连inf的边实际上就是连0边.
#include <cstdio> #include <queue> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 55 * 55,inf = 0x7fffffff; int n,m,ans,a[55][55],cnt,cnt1,cnt2,S,T,pos[maxn][maxn],head[100010],to[100010],nextt[100010],w[100010],tot = 2; int d[100010]; struct node { int x,y,opt; } shu[maxn],heng[maxn]; void add(int x,int y,int z) { //cout << x << " " << y << " " << 1000 - z << endl; w[tot] = z; to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; w[tot] = 0; to[tot] = x; nextt[tot] = head[y]; head[y] = tot++; } bool bfs() { queue <int> q; q.push(S); memset(d,-1,sizeof(d)); d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); if (u == T) return true; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (w[i] && d[v] == -1) { d[v] = d[u] + 1; q.push(v); } } } return false; } int dfs(int u,int f) { if (u == T) return f; int res = 0; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (d[v] == d[u] + 1 && w[i]) { int temp = dfs(v,min(f - res,w[i])); w[i] -= temp; w[i ^ 1] += temp; res += temp; if (res == f) return res; } } if (!res) d[u] = -1; return res; } void dinic() { while (bfs()) ans -= dfs(S,inf); } int main() { scanf("%d%d",&n,&m); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { scanf("%d",&a[i][j]); if (a[i][j] < 0) { if (a[i][j] == -1 || a[i][j] == -2) { node temp; temp.x = i; temp.y = j; temp.opt = a[i][j]; shu[++cnt1] = temp; } else { node temp; temp.x = i; temp.y = j; temp.opt = a[i][j]; heng[++cnt2] = temp; } } } for (int i = 1; i <= cnt1; i++) { if (shu[i].opt == -1) for (int j = 1; j <= shu[i].x; j++) pos[i][j] = ++cnt; else for (int j = 1; j <= n - shu[i].x + 1; j++) pos[i][j] = ++cnt; } for (int i = 1; i <= cnt2; i++) { if (heng[i].opt == -3) for (int j = 1; j <= heng[i].y; j++) pos[i + cnt1][j] = ++cnt; else for (int j = 1; j <= m - heng[i].y + 1; j++) pos[i + cnt1][j] = ++cnt; } ans = 1000 * (cnt1 + cnt2); S = ++cnt; T = ++cnt; for (int i = 1; i <= cnt1; i++) { if (shu[i].opt == -1) { for (int j = 1; j <= shu[i].x; j++) { if (j != shu[i].x) add(pos[i][j],pos[i][j + 1],1000 - a[shu[i].x - j][shu[i].y]); else add(pos[i][j],T,1000); if (j == 1) add(S,pos[i][j],1000); } } else { for (int j = 1; j <= n - shu[i].x + 1; j++) { if (j != n - shu[i].x + 1) add(pos[i][j],pos[i][j + 1],1000 - a[shu[i].x + j][shu[i].y]); else add(pos[i][j],T,1000); if (j == 1) add(S,pos[i][j],1000); } } } for (int i = 1; i <= cnt2; i++) { if (heng[i].opt == -3) { for (int j = 1; j <= heng[i].y; j++) { if (j != heng[i].y) add(pos[i + cnt1][j],pos[i + cnt1][j + 1],1000 - a[heng[i].x][j]); else add(pos[i + cnt1][j],T,1000); if (j == 1) add(S,pos[i + cnt1][j],1000); } } else { for (int j = 1; j <= m - heng[i].y + 1; j++) { if (j != m - heng[i].y + 1) add(pos[i + cnt1][j],pos[i + cnt1][j + 1],1000 - a[heng[i].x][m - j + 1]); else add(pos[i + cnt1][j],T,1000); if (j == 1) add(S,pos[i + cnt1][j],1000); } } } for (int i = 1; i <= cnt1; i++) for (int j = 1; j <= cnt2; j++) { int X,Y; if (shu[i].opt == -1 && heng[j].opt == -4) //上右 { if (shu[i].x < heng[j].x || shu[i].y < heng[j].y) continue; X = heng[j].x; Y = shu[i].y; int temp1 = shu[i].x - X; int temp2 = m - Y + 2; add(pos[i][temp1],pos[j + cnt1][temp2],1000); } if (shu[i].opt == -1 && heng[j].opt == -3) //上左 { if (shu[i].x < heng[j].x || shu[i].y > heng[j].y) continue; X = heng[j].x; Y = shu[i].y; int temp1 = shu[i].x - X; int temp2 = Y + 1; add(pos[i][temp1],pos[j + cnt1][temp2],1000); } if (shu[i].opt == -2 && heng[j].opt == -4) //下右 { if (shu[i].y < heng[j].y || shu[i].x > heng[j].x) continue; X = heng[j].x; Y = shu[i].y; int temp1 = X - shu[i].x; int temp2 = m - Y + 2; add(pos[i][temp1],pos[j + cnt1][temp2],1000); } if (shu[i].opt == -2 && heng[j].opt == -3) //下左 { if (shu[i].x > heng[j].x || shu[i].y > heng[j].y) continue; X = heng[j].x; Y = shu[i].y; int temp1 = X - shu[i].x; int temp2 = Y + 1; add(pos[i][temp1],pos[j + cnt1][temp2],1000); } } dinic(); printf("%d\n",ans); return 0; }