NOI 2004~2006
Posted linda-fcj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOI 2004~2006相关的知识,希望对你有一定的参考价值。
[NOI2005]聪聪与可可
https://wenku.baidu.com/view/90adb02acfc789eb172dc8a8.html
用n次spfa求出当聪聪在i位置,可可在j位置时,聪聪走的第一步。
同f[i][j]表示聪聪在i位置,可可在j位置时聪聪吃到可可的期望步数。
当聪聪在i位置,可可在j位置时,聪聪所走的路线是确定的(走距离可可最近的点(如果有多个走标号最小的))。
如果聪聪与可可在同一个位置,聪聪已经吃到可可了,期望为0.
那么:
f[i][j] =
1.i == j , 0;
2.path[i][j] == j || path[path[i][j]][j] == j , 1;
3.如果聪聪不能在一次选择中吃到可可,那么她吃到可可的期望就与可可所做的选择有关了
f[i][j] = (f[path[path[i][j]]][j](可可还停留在在j位置) + ∑(f[path[path[i][j]][j]][v])(v表示与j相邻的点) ) / (deg[j] + 1) + 1;(每个选择的概率1 / (deg[j] + 1))
记忆化搜索实现:
代码:
// luogu-judger-enable-o2 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn=1010; struct point { int to; int nxt; }edge[maxn*2]; int n,m,tot,S,T; int head[maxn],p[maxn][maxn],dis[maxn],vis[maxn],du[maxn]; double f[maxn][maxn]; inline void add(int u,int v) { tot++; edge[tot].to=v; edge[tot].nxt=head[u]; head[u]=tot; } inline void spfa(int s) { queue<int> q; memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) dis[i]=1e9; dis[s]=0,vis[s]=1; q.push(s); while(!q.empty()) { int tt=q.front(); q.pop(); vis[tt]=0; for(int i=head[tt];i;i=edge[i].nxt) { int v=edge[i].to; if(dis[v]>dis[tt]+1) { dis[v]=dis[tt]+1; p[v][s]=tt; if(!vis[v]) vis[v]=1,q.push(v); } else if(dis[v]==dis[tt]+1) p[v][s]=min(p[v][s],tt); } } } inline double dfs(int x,int y) { if(x==y) return 0.0; if(p[x][y]==y || p[p[x][y]][y]==y) return 1.0; if(f[x][y]!=-1.0) return f[x][y]; f[x][y]=0.0; for(int i=head[y];i;i=edge[i].nxt) { int v=edge[i].to; f[x][y]+=dfs(p[p[x][y]][y],v)/du[y]; } f[x][y]+=dfs(p[p[x][y]][y],y)/du[y]; f[x][y]+=1; return f[x][y]; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=-1.0; scanf("%d%d",&S,&T); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v),add(v,u); du[v]++,du[u]++; } for(int i=1;i<=n;i++) du[i]++; for(int i=1;i<=n;i++) spfa(i); printf("%.3lf\n",dfs(S,T)); return 0; }
[NOI2005]瑰丽华尔兹
f[i][j]表示从( i , j )开始的最长滑行距离,有f[i][j]=f[x][y]+dis( i , j , x , y );
因为不能拐弯,所以依照时间顺序,按照船的倾斜方向更新每一格的f值,取所有的f值的max
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int maxn=202; char map[maxn][maxn]; pair<int,int> q[maxn],tmp; int n,m,k,h,t,ans; int dx[]={0,-1,1,0,0}; int dy[]={0,0,0,-1,1}; int f[maxn][maxn]; inline void solve(int xx,int yy,int dd,int T) { int now=0; h=t=0; while(xx>=1 && xx<=n && yy>=1 && yy<=m) { if(map[xx][yy]==‘x‘) h=t=0; else { tmp.first=f[xx][yy],tmp.second=now; while(h<t && q[t-1].first+now-q[t-1].second<=tmp.first) t--; q[t++]=tmp; while(h<t && (now-q[h].second)>T) h++; f[xx][yy]=q[h].first+(now-q[h].second); ans=max(ans,f[xx][yy]); } xx+=dx[dd],yy+=dy[dd]; now++; } } int main() { int x,y; scanf("%d%d%d%d%d",&n,&m,&x,&y,&k); for(int i=1;i<=n;i++) scanf("%s",map[i]+1); memset(f,0x80,sizeof(f)); f[x][y]=0; for(int i=1,s,e,d,len;i<=k;i++) { scanf("%d%d%d",&s,&e,&d),len=e-s+1; if(d==1) for(int j=1;j<=m;j++) solve(n,j,1,len); if(d==2) for(int j=1;j<=m;j++) solve(1,j,2,len); if(d==3) for(int j=1;j<=n;j++) solve(j,m,3,len); if(d==4) for(int j=1;j<=n;j++) solve(j,1,4,len); } printf("%d\n",ans); return 0; }
以上是关于NOI 2004~2006的主要内容,如果未能解决你的问题,请参考以下文章