Forest Program dfs+tanjar仙人掌
題目鏈接?CCPC2019 F題。
題意:給一顆仙人掌樹,讓你求每一個小環(huán)的邊的個數(shù),用快速冪即可求解。
思路:第一反應是tanjar亂搞,把每個環(huán)上的點取出來,類似于縮點的方法。但是忽然感覺dfs能做,因為仙人掌比較特殊的性質,就是一個環(huán)上不會有多個分支。
那么首先我們從任一點出發(fā),dfs下去記錄深度并且標記,當我們到達一個點標記過且深度小于當前點,證明我們剛好走了一個環(huán),那么兩點的深度差+1就是該環(huán)的邊數(shù),如果碰到標記過深度比當前點深度大呢,其實這個就是我們之前已經處理過的環(huán)了,直接跳過不管就行,就這樣就完了。
dfs代碼:
#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>
#include<list>
#include<time.h>
#define myself i,l,r
#define lson i<<1
#define rson i<<1|1
#define Lson i<<1,l,mid
#define Rson i<<1|1,mid+1,r
#define half (l+r)/2
#define lowbit(x) x&(-x)
#define min4(a, b, c, d) min(min(a,b),min(c,d))
#define min3(x, y, z) min(min(x,y),z)
#define max3(x, y, z) max(max(x,y),z)
#define max4(a, b, c, d) max(max(a,b),max(c,d))
typedef unsigned long long ull;
typedef long long ll;
#define pii make_pair
#define pr pair<int,int>
const int inff = 0x3f3f3f3f;
const long long inFF = 9223372036854775807;
const int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
const int mdir[8][2] = {0, 1, 0, -1, 1, 0, -1, 0, 1, 1, -1, 1, 1, -1, -1, -1};
const double eps = 1e-10;
const double PI = acos(-1.0);
const double E = 2.718281828459;
using namespace std;
const int mod=998244353;
const int maxn=3e5+5;
const int maxm=1e6+5;
struct node
{int to,p;
}edge[maxm];
int head[maxn],sign;
int vis[maxn];
int n,m;
ll res;
ll qmod(ll a,ll b)
{ll ans=1;while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans;
}
ll qqmod(ll a,ll b)
{ll ans=qmod(a,b);ans=(ans-1+mod)%mod;return ans;
}
void init()
{for(int i=0;i<=n;i++) head[i]=-1,vis[i]=0;sign=0;
}
void add(int u,int v)
{edge[sign]=node{v,head[u]};head[u]=sign++;
}
void dfs(int u,int cnt)
{vis[u]=cnt;for(int i=head[u];~i;i=edge[i].p){int v=edge[i].to;if(vis[v]){if(vis[u]-vis[v]>1)//判斷是不是走了父親節(jié)點{ll c=vis[u]-vis[v]+1;res=res*qqmod(2,c)%mod;m-=c;}}else dfs(v,cnt+1);}
}
int main()
{int x,y;while(scanf("%d %d",&n,&m)!=EOF){if(m==0){puts("0");continue;}init();for(int i=1;i<=m;i++){scanf("%d %d",&x,&y);add(x,y),add(y,x);}res=1;dfs(1,1);res=res*qmod(2,m)%mod;printf("%lld\n",res);}return 0;
}
然后就是tanjar的做法。
其實很多人用點雙做這道題我覺得沒必要,而且我寫的一直超時(-.-
問題在于tanjar求聯(lián)通分量其實是求大環(huán),就是第二個樣例其實就是一個大的連通分量
但是大概思路都是一樣的,也當是復習一哈。
當我們tanjar到一個點low[v]>=low[u]證明u點是一個割點,我們縮點的方法是把stack中直到等于u的點全部取出來
這里就是直到等于v的點全部取出來就行,然后+1就是該塊(塊描述應該是沒問題)的數(shù)量求出來了,
只有塊數(shù)量大于2才算一個環(huán)
代碼是T的,不曉得為啥~(希望大佬能幫助一下!
//#pragma comment (linker, "/STACK:102400000,102400000")
//#include<bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>
#include<list>
#include<time.h>
#define myself i,l,r
#define lson i<<1
#define rson i<<1|1
#define Lson i<<1,l,mid
#define Rson i<<1|1,mid+1,r
#define half (l+r)/2
#define lowbit(x) x&(-x)
#define min4(a, b, c, d) min(min(a,b),min(c,d))
#define min3(x, y, z) min(min(x,y),z)
#define max3(x, y, z) max(max(x,y),z)
#define max4(a, b, c, d) max(max(a,b),max(c,d))
typedef unsigned long long ull;
typedef long long ll;
#define pii make_pair
#define pr pair<int,int>
const int inff = 0x3f3f3f3f;
const long long inFF = 9223372036854775807;
const int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
const int mdir[8][2] = {0, 1, 0, -1, 1, 0, -1, 0, 1, 1, -1, 1, 1, -1, -1, -1};
const double eps = 1e-10;
const double PI = acos(-1.0);
const double E = 2.718281828459;
using namespace std;
const int mod=998244353;
const int maxn=3e5+5;
const int maxm=1e6+5;
struct node
{int to,p;
}edge[maxm];
int head[maxn],sign;
int n,m;
int Stack[maxn],low[maxn],dfn[maxn];
int num[maxn];
int top,t,cnt;
ll p[maxn],r[maxn];
ll res;
ll qmod(ll a,ll b)
{if(r[b]) return r[b];int c=b;ll ans=1;while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}return r[c]=ans;
}
ll qqmod(ll a,ll b)
{if(p[b]) return p[b];ll ans=qmod(a,b);ans=(ans-1+mod)%mod;return p[b]=ans;
}
void init()
{t=top=cnt=sign=0;for(int i=1;i<=n;i++){low[i]=dfn[i]=0;head[i]=-1;}
}
void add(int u,int v)
{edge[sign]=node{v,head[u]};head[u]=sign++;
}
void tanjar(int u,int pre)
{dfn[u]=low[u]=++t;Stack[++top]=u;for(int i=head[u];~i;i=edge[i].p){int v=edge[i].to;if(v==pre) continue;if(!dfn[v]){tanjar(v,u);low[u]=min(low[u],low[v]);if(low[v]>=dfn[u]){cnt++;num[cnt]=0;int x;do{x=Stack[top--];num[cnt]++;}while(x!=v);num[cnt]++;}}else low[u]=min(low[u],dfn[v]);}
}
int main()
{while(scanf("%d %d",&n,&m)!=EOF){if(m==0) {puts("0");continue;}init();int x,y;for(int i=1;i<=m;i++){scanf("%d %d",&x,&y);add(x,y),add(y,x);}res=1;for(int i=1;i<=n;i++)if(!dfn[i]) tanjar(i,i);for(int i=1;i<=cnt;i++)if(num[cnt]>=3) res=res*qqmod(2,num[cnt])%mod,m-=num[cnt];res=res*qmod(2,m)%mod;printf("%lld\n",res);}
}
?
總結
以上是生活随笔為你收集整理的Forest Program dfs+tanjar仙人掌的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU - 3183 A Magic L
- 下一篇: Invoker 2019CCPC秦皇岛站