1. 程式人生 > >D9 圖論綜合題

D9 圖論綜合題

i++ += splay 需要 long nbsp close else 如果

1.白銀蓮花池

LUOGU 2411

第一種思路:當然我們可以寫三個bfs a掉這個題,這寫下來一二百行要有了吧;

第二種:我們可以在一個bfs中維護所有的信息,一個方向數組,從起點開始,向八個方向擴展,如果添加的蓮花需要少,就更新當前的值,如果添加蓮花一樣多但所需步數更少,也更新,目標點方案數等於當前點方案數。特別地,如果添加蓮花和步數一樣多,目標點方案數加上當前點方案數。以上三種情況目標點皆需入隊;

int add[50][50],bs[50][50],vis[50][50],sx,sy,tx,ty,n,m,w[500][500];
long long ans,c,hl[500][500];//add數組表示需要添加蓮花的最小值,bs表示需要的最小步數,hl表示方案數;

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch==-) f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
int dx[9]={-2,-1,1,2,2,1,-1,-2}; int dy[9]={1,2,2,1,-1,-2,-2,-1}; int add[50][50],bs[50][50],vis[50][50],sx,sy,tx,ty,n,m,w[500][500]; long long ans,c,hl[500][500]; queue<pii>q; int main() { //freopen("silvlily.in","r",stdin); //freopen("silvlily.out","w",stdout); m=read();n=read(); for
(int i=1;i<=m;i++) for(int j=1;j<=n;j++) { w[i][j]=read(); if(w[i][j]==4) tx=i,ty=j; if(w[i][j]==3) { q.push(make_pair(i,j)); vis[i][j]=1; hl[i][j]=1; //sx=i,sy=j; } else add[i][j]=1e9,bs[i][j]=1e9; } int a,b,x,y,flag; while(q.size()) { x=q.front().first,y=q.front().second; q.pop(); vis[x][y]=0; a=add[x][y],b=bs[x][y],c=hl[x][y]; for(int i=0;i<8;i++) { int xx=x+dx[i],yy=y+dy[i],flag=0; if(xx<1||xx>m||yy<1||yy>n||w[xx][yy]==2||a>add[xx][yy]) continue; if(w[xx][yy]) { if(a<add[xx][yy]||b+1<bs[xx][yy]) add[xx][yy]=a,bs[xx][yy]=b+1,hl[xx][yy]=c,flag=1; else if(b+1==bs[xx][yy]) hl[xx][yy]+=c,flag=1; } else if(a+1<add[xx][yy]||(a+1==add[xx][yy]&&b+1<bs[xx][yy])) add[xx][yy]=a+1,bs[xx][yy]=b+1,hl[xx][yy]=c,flag=1; else if(a+1==add[xx][yy]&&b+1==bs[xx][yy]) hl[xx][yy]+=c,flag=1; if(flag&&!vis[xx][yy]&&(xx!=tx||yy!=ty)) q.push(make_pair(xx,yy)),vis[xx][yy]=1; } } //cout<<hl[tx][ty]<<endl; if(add[tx][ty]==1e9) { cout<<"-1"<<endl; return 0; } else cout<<add[tx][ty]<<endl<<bs[tx][ty]<<endl<<hl[tx][ty]<<endl; return 0; }
View Code

2.跳樓機

LUOGU 3403

寫這個題有點難受,讀錯題了然後考慮只有x,y是以為是組合數,想成有年數學自招題了,我哭遼...

又有點像背包 1e18 呵呵,放棄,但再仔細想想,這個題和墨墨的等式有點像啊,墨墨的題解;

在老師的指引下,我們可以列出公式ans+=(h-i*x)/y;;

表示通過 y,z兩個操作可以到達的 mod x=i最小的樓層。

可以得知:f[i+y]=f[i]+y,f[i+z]=f[i]+z.

洛谷這個題解感覺很棒:https://fengzi8615.blog.luogu.org/solution-p3403

f(i)表示表示僅通過操作2和操作3能到達的 modx == i 的最小樓層

很容易得出狀態轉移方程

  • f(i+y)=f(i)+yf(i+y)=f(i)+y;
  • f(i+z)=f(i)+zf(i+z)=f(i)+z;

能到達mod x=i+y的最小樓層
即在能到達mod x=i的最小樓層的基礎上,再執行一遍操作2

我們來看看最短路的求法 f(y)=f(x)+edge(i)

y是子結點,x是父節點,edge表示權值
這個寫法跟我們上面的轉移方程很像誒
於是考慮讓(i+y)(i+z)成為點;
y,z成為權值從而算出f(i);

ans+=(h-f[i])/x +1
由於f(i)是在不適用操作1的情況下
所以hf(i)之間的差值由操作1來完成
而每進行操一次作1,我們就可以到達一個新的樓層
所以答案就要累加上進行操作1的次數

(h-f[i])/x +1

為什麽要+1呢,因為除法是向下取整,註意由於f數組的存在,是不可能出現剛好被整除的,這一點請自己思考;

D9 圖論綜合題