赞
踩
P2016 战略游戏
P2730 [USACO3.2]魔板 Magic Squares
P1379 八数码难题
P3393 逃离僵尸岛
1.战略游戏
最小权覆盖集问题
树形dp:思路:
1.递归搜索预处理
2.回溯DP求最值
主要决策就是选与不选,所以可以设定状态&方程
f[i][0]为:当不在i号节点放士兵时,以i为根的子树上最少需要设置的士兵数
f[i][1]为:当在i号节点放士兵时,以i为根的子树上最少需要设置的士兵数
转移方程:
x为父亲节点,y为儿子节点
f[x][0]+=f[y][1];
f[x][1]+=min(f[y][0],f[y][1]);
1.预处理设定一个根(根的选取不影响结果,但是要注意儿子和父亲关系的对应,详见代码),从根节点递归,枚举儿子节点继续递归直到当前节点为叶子节点时开始回溯
2.回溯过程中dp,列转移方程,完事
最后输出根节点选与不选的最小值即可
#include <bits/stdc++.h> using namespace std; int n,fa[1505],f[1505][2]; vector<int> son[1505]; int read() { int x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-')f=-1;ch=getchar();} while (isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } void find(int x) { for (int i=0;i<son[x].size();i++) { int y=son[x][i]; find(y); f[x][0]+=f[y][1]; f[x][1]+=min(f[y][0],f[y][1]); } } int main() { n=read(); for (int i=0;i<n;i++) { int node1=read(),sum=read(); for (int j=1;j<=sum;j++)//严格对应父子关系 { int node2=read(); if (fa[node2]==node2||fa[node2]) { son[node2].push_back(node1); fa[node1]=node2; } else { son[node1].push_back(node2); fa[node2]=node1; } } f[i][1]=1; } find(0); printf("%d",min(f[0][1],f[0][0])); return 0; }
2.魔板 Magic Squares
3.八数码难题
同类型的map宽搜题型,主要思路:
将一个二维的状态进行运算转移成一个数字(魔板最多八位,九宫格最多9位,开long long),然后将这个数字映射->对应情况的答案
在宽搜过程中使用临时的一个数组(从队列中取出状态后,将其逆运算转换回数字形态,并在数组上更新状态,如:与四周某个方块交换位置),和一个临时的状态(在数组更新状态后,又重新转换为数字的形式,进行map中的count查找排重,选最优解),用该状态排重,如果在之前没有遍历过,将该种状态map映射答案,并加入队列进行下一步拓展更新,最后只要找到结束状态,输出并结束程序
思想:状态转换,map
完事
魔板 Magic Squares
#include <bits/stdc++.h> #define ll long long using namespace std; queue<ll> q; ll a[10][10],n,nn; map<ll,string> m; void f(char c) { if (m.count(nn)==0) { m[nn]=m[n]+c; q.push(nn); } } int main() { ll fn=0; for (ll i=1;i<=2;i++) { ll x1,x2,x3,x4; if (i==1) scanf("%lld %lld %lld %lld",&x1,&x2,&x3,&x4); else scanf("%lld %lld %lld %lld",&x4,&x3,&x2,&x1); fn=fn*10+x1; fn=fn*10+x2; fn=fn*10+x3; fn=fn*10+x4; } q.push(12348765); while (!q.empty()) { n=q.front(),nn=n; q.pop(); if (n==fn) { string s=m[n]; ll len=s.length(); printf("%lld\n",len); for (ll i=0;i<len;i++) printf("%c",s[i]); return 0; } for (ll i=2;i>=1;i--) for (ll j=4;j>=1;j--) a[i][j]=nn%10,nn/=10; //A nn=0; for (ll i=2;i>=1;i--) for (ll j=1;j<=4;j++) nn=nn*10+a[i][j]; f('A'); //B nn=0; a[1][0]=a[1][4]; a[2][0]=a[2][4]; for (ll i=1;i<=2;i++) for (ll j=0;j<=3;j++) nn=nn*10+a[i][j]; f('B'); //C nn=0; swap(a[1][2],a[1][3]); swap(a[1][2],a[2][3]); swap(a[1][2],a[2][2]); for (ll i=1;i<=2;i++) for (ll j=1;j<=4;j++) nn=nn*10+a[i][j]; f('C'); swap(a[1][2],a[1][3]); swap(a[1][3],a[2][3]); swap(a[2][2],a[2][3]); } return 0; }
八数码难题
#include <bits/stdc++.h> #define ll long long using namespace std; queue<ll> q; int fx[4][2]={{0,-1},{0,1},{-1,0},{1,0}}; ll n,qx,qy,a[5][5]; map<ll,ll> m; int main() { scanf("%lld",&n); if (n==123804765) { printf("%lld",0); return 0; } q.push(n); m[n]=0; while (!q.empty()) { n=q.front(); q.pop(); ll nn=n; if (n==123804765) { printf("%lld",m[n]); return 0; } for (int i=3;i>=1;i--) for (int j=3;j>=1;j--) { a[i][j]=nn%10,nn/=10; if (a[i][j]==0) qx=i,qy=j; } for (int i=0;i<4;i++) { nn=0; int xx=qx+fx[i][0],yy=qy+fx[i][1]; if (xx>=1&&xx<=3&&yy>=1&&yy<=3) { swap(a[qx][qy],a[xx][yy]); for (int i=1;i<=3;i++) for (int j=1;j<=3;j++) nn=nn*10+a[i][j]; if (m.count(nn)==0) { m[nn]=m[n]+1; q.push(nn); } swap(a[qx][qy],a[xx][yy]); } } } return 0; }
4.逃离僵尸岛
思路:bfs+最短路
1.先将每个僵尸城加入到队列中,bfs更新图上的信息,找出安全城市和危险城市,更新其价格,主要标记是否已经遍历,小优化:当扩展点的距离已经超过了危险范围,可以将改点不入队列
2.开始愉快的dijsktra,注意将边权转换为点权,起点终点权值为0
完事
#include <bits/stdc++.h> #define ll long long using namespace std; const ll inf=1e18; const int maxn=1e5+5; struct edge { int v,next; }a[4*maxn]; struct dij { int num; ll len; friend bool operator < (dij x,dij y)//优先队列优化 { return x.len>y.len; } }; priority_queue<dij> q;//最短路更新队列 queue<int> qq;//bfs队列 ll dis[maxn],w[maxn],p,Q;//w点权值 dis最短距离 int cnt,n,m,k,s,c[maxn],stp[maxn],head[maxn];//c:僵尸城(可以省略),stp:bfs距离 int dgr[maxn];//1僵尸 2危险 0安全 bool bj[maxn],bjj[maxn];//bj:bfs标记 bjj:dijkstra标记 int read() { int x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-')f=-1;ch=getchar();} while (isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } void add(int u,int v) { cnt++; a[cnt].v=v; a[cnt].next=head[u]; head[u]=cnt; } void bfs() { while (!qq.empty()) { int u=qq.front(); qq.pop(); for (int i=head[u];i;i=a[i].next) { int v=a[i].v; if (bj[v]==1||dgr[v]==1) continue; bj[v]=1; stp[v]=stp[u]+1; if (stp[v]<=s) { qq.push(v); dgr[v]=2; } } } } void benew() { for (int i=2;i<n;i++) { if (dgr[i]==0) w[i]=(ll)p; else if (dgr[i]==2) w[i]=(ll)Q; } } void dijkstra() { for (int i=2;i<=n;i++) dis[i]=inf; q.push(dij{1,0}); while (!q.empty()) { dij x=q.top(); q.pop(); int u=x.num; if (bjj[u]==1) continue; bjj[u]=1; for (int i=head[u];i;i=a[i].next) { int v=a[i].v; if (dgr[v]==1) continue; ll ww=w[v]; if (dis[v]>dis[u]+ww) { dis[v]=dis[u]+ww; q.push(dij{v,dis[v]}); } } } } int main() { n=read(),m=read(),k=read(),s=read(); p=read(),Q=read(); for (int i=1;i<=k;i++) { c[i]=read(); dgr[c[i]]=1; qq.push(c[i]); } for (int i=1;i<=m;i++) { int x=read(),y=read(); add(x,y); add(y,x); } bfs(); benew(); dijkstra(); printf("%lld",dis[n]); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。