• 炸弹


    题目



    解题思路

    注意到图的特点是一棵树,那我们就把这棵树建出来,如果炸掉某个点(p)使点(i)也消失,则点i在树上为点(p)的父亲/兄弟/儿子,如样例:
    '#123'
    '45##'
    '#6##'
    2
    /
    1 3
    /
    5 6
    /
    4
    具体做法可以先选一个只能单向(上下、左右)扩展的点,然后搜索一下。接着树形(dp)(f_{x,0/1/2})分别表示 (0:x)不放炸弹且x没被炸;(1:x)不放炸弹但x已被炸;(2:x)放炸弹 的最小炸弹数。方程:
    (f_{x,0}=sum f_{son,1})

    (f_{x,1}=min( f_{p,2} + sum min(f_{son,0},f_{son,1},f_{son,2}) ) 满足(p∈x的儿子 son≠p))

    (f_{x,2}=sum min(f_{son,0},f_{son,1},f_{son,2}) + 1)

    (f_{x,1})时用个小优化就可以(O(n))

    Code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int a[55][55],n,m,tot = 0,f[2505][3],h[2505];
    int dx[4] = {1,0,-1,0},dy[4] = {0,1,0,-1};
    char s[55];
    
    struct nd{
    	int x,y,c;
    }q[2505];
    struct edge{
    	int to,nxt;
    }e[5000];
    void add(int x,int y)
    {
    	e[++tot] = (edge){y,h[x]};
    	h[x] = tot;
    }
    void bfs(int x,int y)
    {
    	int head = 0,tail = 0,l = 1;
    	q[++tail].x = x;
    	q[tail].y = y;
    	q[tail].c = l;
    	a[x][y] = 0;
    	while (head < tail)
    	{
    		head++;
    		int xx = q[head].x,yy = q[head].y;
    		while (a[xx - 1][yy]) 
    			xx--,a[xx][yy] = 0,q[++tail].x = xx,q[tail].y = yy,l++,
    			add(q[head].c,l),add(l,q[head].c),q[tail].c = l;
    		xx = q[head].x;
    		while (a[xx + 1][yy]) 
    			xx++,a[xx][yy] = 0,q[++tail].x = xx,q[tail].y = yy,l++,
    			add(q[head].c,l),add(l,q[head].c),q[tail].c = l;
    		xx = q[head].x;
    		while (a[xx][yy - 1]) 
    			yy--,a[xx][yy] = 0,q[++tail].x = xx,q[tail].y = yy,l++,
    			add(q[head].c,l),add(l,q[head].c),q[tail].c = l;
    		yy = q[head].y;
    		while (a[xx][yy + 1]) 
    			yy++,a[xx][yy] = 0,q[++tail].x = xx,q[tail].y = yy,l++,
    			add(q[head].c,l),add(l,q[head].c),q[tail].c = l;
    	}
    }
    void dfs(int u,int fa)
    {
    	int ms = 2147483647;
    	f[u][2] = 1;
    	for (int i = h[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (v == fa) continue;
    		dfs(v,u);
    		f[u][0] += f[v][1];
    		f[u][1] += min(f[v][0],min(f[v][1],f[v][2]));
    		ms = min(ms,f[v][2] - min(f[v][0],min(f[v][1],f[v][2])));
    		f[u][2] += min(f[v][0],min(f[v][1],f[v][2]));
    	}
    	if (ms != 2147483647) f[u][1] += ms;
    	else f[u][1] = 1e7;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for (int i = 1; i <= n; i++)
    	{
    		scanf("%s",s + 1);
    		for (int j = 1; j <= m; j++)
    			if (s[j] == '.') a[i][j] = 1;
    	}
    	for (int i = 1; i <= n; i++)
    	{
    		int flag = 0;
    		for (int j = 1; j <= m; j++)
    		{
    			if (!a[i][j]) continue;
    			int flag1 = 0,flag2 = 0;
    			if (a[i + 1][j] || a[i - 1][j]) flag1 = 1;
    			if (a[i][j + 1] || a[i][j - 1]) flag2 = 1;
    			if (flag1 == 1 &&  flag2 == 1);
    			else bfs(i,j),flag = 1;
    			if (flag) break;
    		}
    		if (flag) break;
    	}
    	dfs(1,1);
    	printf("%d",min(f[1][1],f[1][2]));
    }
    
  • 相关阅读:
    High Executions Of Statement "delete from smon_scn_time..."
    centos6.5 vmware报错 (could open /dev/vmmon)
    VMware注册码
    VMware 延长bios等待时间
    centos7 修改引导顺序,默认引导windows,引导等待时间
    windows-linux(centos7)双系统-引导修复
    centos设置开机进入桌面模式或命令行模式
    centos 6 进入桌面后键盘和鼠标无法使用
    VMware ESXi
    js获取<input type='file'>的文件名和后缀名
  • 原文地址:https://www.cnblogs.com/nibabadeboke/p/13472210.html
Copyright © 2020-2023  润新知