1. 程式人生 > >bzoj 1415 [Noi2005]聰聰和可可——其實無環的圖上概率

bzoj 1415 [Noi2005]聰聰和可可——其實無環的圖上概率

.net add namespace main 嘗試 targe 判斷 不能 最小

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=1415

乍一看和“遊走”一樣。於是高斯消元。n^2狀態,復雜度n^6……

看看TJ,發現因為聰聰不是隨便走的,所以聰聰一直逼近可可。故其實無環。可以記搜。

(1A還是不錯的)

技術分享圖片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=1005;
int n,m,l0,l1,nxt[N][N],dfn[N],du[N];
double dp[N][N]; bool vis[N],vs[N][N]; priority_queue<int,vector<int>,greater<int> >ed[N]; void add(int x,int y) { ed[x].push(y);ed[y].push(x); du[x]++;du[y]++; } void bfs(int cr) { priority_queue<int,vector<int>,greater<int> >tp; memset(vis,0,sizeof
vis);memset(dfn,0,sizeof dfn); queue<int> q;q.push(cr);vis[cr]=1;nxt[cr][cr]=cr; while(q.size()) { int k=q.front();q.pop(); tp=ed[k]; while(tp.size()) { int v=tp.top();tp.pop(); if(vis[v])continue; dfn[v]=dfn[k]+1;vis[v]=1
;q.push(v); if(dfn[v]>2)nxt[v][cr]=nxt[k][cr]; else nxt[v][cr]=v; } } } double dfs(int x,int y)//coco->x ,cncn->y { // printf("x=%d y=%d\n",x,y); if(vs[x][y])return dp[x][y];vs[x][y]=1; if(nxt[x][y]==x){/*printf("rt x=%d y=%d\n",x,y);*/return dp[x][y]=1;} double ret=(dfs(x,nxt[x][y])+(nxt[x][y]!=x))/(du[x]+1); priority_queue<int,vector<int>,greater<int> >tp=ed[x];//每層定義 // printf("siz[%d]=%d\n",x,tp.size()); while(tp.size()) { int v=tp.top();tp.pop(); // printf("v=%d nxt[%d][%d]=%d\n",v,x,y,nxt[x][y]); ret+=(dfs(v,nxt[x][y])+(nxt[x][y]!=v))/(du[x]+1); } // printf("ret=%.3lf\n",ret); return dp[x][y]=ret; } int main() { scanf("%d%d%d%d",&n,&m,&l0,&l1);int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y);add(x,y); } for(int i=1;i<=n;i++)bfs(i); printf("%.3lf",dfs(l1,l0)); return 0; }
版本1

看看TJ,發現判斷得那麽糾結是因為x==y時正常應返回0。

技術分享圖片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=1005;
int n,m,l0,l1,nxt[N][N],dfn[N],du[N];
double dp[N][N];
bool vis[N],vs[N][N];
priority_queue<int,vector<int>,greater<int> >ed[N];
void add(int x,int y)
{
    ed[x].push(y);ed[y].push(x);
    du[x]++;du[y]++;
}
void bfs(int cr)
{
    priority_queue<int,vector<int>,greater<int> >tp;
    memset(vis,0,sizeof vis);memset(dfn,0,sizeof dfn);
    queue<int> q;q.push(cr);vis[cr]=1;nxt[cr][cr]=cr;
    while(q.size())
    {
        int k=q.front();q.pop();
        tp=ed[k];
        while(tp.size())
        {
            int v=tp.top();tp.pop();
            if(vis[v])continue;
            dfn[v]=dfn[k]+1;vis[v]=1;q.push(v);
            if(dfn[v]>2)nxt[v][cr]=nxt[k][cr];
            else nxt[v][cr]=v;
        }
    }
}
double dfs(int x,int y)//coco->x ,cncn->y
{
    if(vs[x][y])return dp[x][y];vs[x][y]=1;
    if(x==y)return dp[x][y]=0;//
    if(nxt[x][y]==x)return dp[x][y]=1;
    double ret=dfs(x,nxt[x][y])/(du[x]+1)+1;
    priority_queue<int,vector<int>,greater<int> >tp=ed[x];//每層定義 
    while(tp.size())
    {
        int v=tp.top();tp.pop();
        ret+=dfs(v,nxt[x][y])/(du[x]+1);
    }
    return dp[x][y]=ret;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&l0,&l1);int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);add(x,y);
    }
    for(int i=1;i<=n;i++)bfs(i);
    printf("%.3lf",dfs(l1,l0));
    return 0;
}
版本2

但是自己代碼巨慢……想來是用了優先隊列的緣故(為了標號字典序)。嘗試改一改。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=1005;
int n,m,l0,l1,nxt[N][N],dfn[N],du[N],head[N],xnt;
double dp[N][N];
bool vis[N],vs[N][N];
priority_queue<int,vector<int>,greater<int> >ed[N];
struct Edge{
    int next,to;
    Edge(int n=0,int t=0):next(n),to(t) {}
}edge[N<<1];
void add(int x,int y)
{
    edge[++xnt]=Edge(head[x],y);head[x]=xnt;
    edge[++xnt]=Edge(head[y],x);head[y]=xnt;
    ed[x].push(y);ed[y].push(x);
    du[x]++;du[y]++;
}
void bfs(int cr)
{
    priority_queue<int,vector<int>,greater<int> >tp;
    memset(vis,0,sizeof vis);memset(dfn,0,sizeof dfn);
    queue<int> q;q.push(cr);vis[cr]=1;nxt[cr][cr]=cr;
    while(q.size())
    {
        int k=q.front();q.pop();
        tp=ed[k];
        while(tp.size())
        {
            int v=tp.top();tp.pop();
            if(vis[v])continue;
            dfn[v]=dfn[k]+1;vis[v]=1;q.push(v);
            if(dfn[v]>2)nxt[v][cr]=nxt[k][cr];
            else nxt[v][cr]=v;
        }
    }
}
double dfs(int x,int y)//coco->x ,cncn->y
{
    if(vs[x][y])return dp[x][y];vs[x][y]=1;
    if(x==y)return dp[x][y]=0;//
    if(nxt[x][y]==x)return dp[x][y]=1;
    double ret=dfs(x,nxt[x][y])/(du[x]+1)+1;
    for(int i=head[x];i;i=edge[i].next)
        ret+=dfs(edge[i].to,nxt[x][y])/(du[x]+1);
    return dp[x][y]=ret;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&l0,&l1);int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);add(x,y);
    }
    for(int i=1;i<=n;i++)bfs(i);
    printf("%.3lf",dfs(l1,l0));
    return 0;
}

結果只是快了28ms。

別人用一些方法保證字典序。

這個人bfs+兩步保證dis最小的前提下調整標號至最小。https://blog.csdn.net/clove_unique/article/details/62237321

這個人spfa的同時判斷標號。(但只能記錄一步的pre)https://blog.csdn.net/PoPoQQQ/article/details/40896403(bfs因為是bfs所以不能邊求dis邊調整標號)

可是我都沒記錄dis。用的dfn。所以懶得改了……比較欣賞第一個人的寫法。

bzoj 1415 [Noi2005]聰聰和可可——其實無環的圖上概率