Time of Update: 2018-12-05
POJ 3352 跟POJ 3177其實是一樣的,只不過3177可能有重邊,要特判。3352問改造後去掉一條邊仍然連通,3177問改造後任意兩點至少有兩條不同的路,其實是一樣的,都是先找出橋,把各分量縮成一點變成一棵樹,結果就是(子葉數+1)/2#define N 1005vector<int> v[N];int low[N];bool vis[N];int du[N];int cnt;void dfs(int u,int fa){ vis[u] = 1; int i;
Time of Update: 2018-12-05
/*構建一棵dfs樹,序列dfn[i]為深度優先數,表示dfs時訪問i節點的序號,low[i]表示從i節點出發能訪問到的最小的深度優先數。若且唯若節點u滿足如下兩個條件之一時,u為割點:1.u為dfs樹的根,且u至少有兩個子節點。2.u不是dfs樹的根,至少存在一個節點v是u的子節點,且low[v]>=dfn[u]。若u為割點,記subnets[u]為u的子節點數,則去掉u後,圖被分成subnets[u]+1個部分(每個子節點的部分和u的祖先的部分),若u為dfs樹的根,則分成subnet
Time of Update: 2018-12-05
#define N 110int g[N][N];int dis[N][N];int ans[N];int p[N][N];//記錄i——j之間的路徑int n,m;int minm;int cnt;int mid;void floyd(){ int i,j,k; for(k=1;k<=n;k++){ //求環 for(i=1;i<k;i++){ for(j=1;j<i;j++){
Time of Update: 2018-12-05
注意樹狀數組的初始化,c[i][j] = lowbit(i)*lowbit(j)與add(i,j,1)等價!因為樹狀數組的lowbit作用是提取出x的最低位1.#define N 1100int c[N][N];int g[N][N];int lowbit(int x){ return x&(-x);}void add(int i,int j,int x){ int tmp; while(i<N){ tmp = j;
Time of Update: 2018-12-05
演算法之LCA與RMQ問題1、 概述LCA(Least Common Ancestors),即最近公用祖先,是指這樣一個問題:在有根樹中,找出某兩個結點u和v最近的公用祖先(另一種說法,離樹根最遠的公用祖先)。 RMQ(Range Minimum/Maximum
Time of Update: 2018-12-05
RMQ預先處理的複雜度為O(nlgn),詢問的複雜度為O(1)//離散化:從小到大記錄這個序列每個值的起始位置、結束位置和頻數#define N 100010int max(int a,int b){return a>b?a:b;}int dp[18][N];//dp[i][j]表示從j開始,長度為2^i區間最大值(最小值)int f[N];//以相同的數為一區間,記錄頻率int s[N],t[N];//離散化,記錄左右區間下標int n,m;void init_rmq(){
Time of Update: 2018-12-05
暴力dfs,先假設全部為白色,然後枚舉每個點,對每個點dfs亂搞,網上搜了下可以用最大團做,沒見過,先放在這裡,學會了再做一遍!#define N 102int color[N];int g[N][N];int maxm,len;int n;int ans[N];int num;void dfs(int u){//0——白色,1——黑色 int i,j; if(u == n+1){//注意處理要完所有點! if(len>maxm){
Time of Update: 2018-12-05
#define N 1000005int c4[N*5],c7[N*5];int c47[N*5],c74[N*5];bool mark[N*5];char str[N];void up(int id){ c4[id] = c4[id<<1] + c4[id<<1|1]; c7[id] = c7[id<<1] + c7[id<<1|1]; c47[id] = max(c47[id<<1] + c7[id<<
Time of Update: 2018-12-05
以後再補解題報告,先貼代碼http://acm.hdu.edu.cn/showproblem.php?pid=3275#define N 100005char str[N];int sum0[N*4],sum1[N*4];bool mark[N*4];void up(int id){ sum0[id] = sum0[id<<1] + sum0[id<<1|1]; sum1[id] = sum1[id<<1] + sum1[id<<1|1
Time of Update: 2018-12-05
開兩個dp數組分別記錄最大值和最小值就ok。#define N 50010int max(int a,int b){return a>b?a:b;}int dp1[20][N];int dp2[20][N];int f[N];int n,m;void init_rmq(){ int i,j; for(i=1;i<=n;i++){ dp1[0][i] = f[i]; dp2[0][i] = f[i]; } int t = floor(
Time of Update: 2018-12-05
求三點的最短路徑和,先求出兩兩之間的路徑和,再除以2就是答案,可以把它看作數軸上的三點,另外,這還可以推廣到一般情況由於zoj掛了,暫時放在這裡,應該可以過的2月8日更新:wa了一次,原因是預先處理dp數組的第二維開小一倍,本來是re才對,結果返回wa,最討厭這樣子...#define N 50010struct edge{ int v; int len; int next;}e[2*N];int ecnt;int head[N];bool vis[N];int
Time of Update: 2018-12-05
oj的資料可能有點問題,貌似連通與不連通都可以過,保守起見,用並查集判斷是否連通,添加虛根弄成一棵樹再用離線rmq#define N 40010struct edge{ int v; int len; int next;}e[2*N];int ecnt;int head[N];bool vis[N];int n;//點數int R[N];//第一次出現i點下標int p[N*2];//記錄路徑點編號int dis[N];//與根的距離int dep[2*N];//深度int
Time of Update: 2018-12-05
注意查詢時當左右兩個區間可以合并的情況min(mid-x+1, t[id<<1].rm) + min(y-mid, t[id<<1|1].lm)#define N 100005struct node{ int l,r; int lm,rm; int mx;}t[N*4+1000];int a[N+100];inline void up(int id){ t[id].lm = t[id<<1].lm; if(t[id<<
Time of Update: 2018-12-05
這裡有可能不連通,可以通過添加一個虛根把森林變成樹,最後如果LCA(u,v) = 0就表示不連通個人比較喜歡用離線演算法,tarjan還需要掌握#define N 10010struct edge{ int v; int len; int next;}e[2*N];int ecnt;int head[N];bool vis[N];int n;//點數int R[N];//第一次出現i點下標int p[N*2];//記錄路徑點編號int dis[N];//與根的距離int
Time of Update: 2018-12-05
http://poj.org/problem?id=2151題意:有M道題,T支隊,給出每支隊ac每道題的機率,問每支隊ac至少1道題並且冠軍ac的題數>=N的機率。方法:先對每支隊進行dp,設dp[i][j]表示前i題ac了j題的機率,轉移方程:dp[i][j] =
Time of Update: 2018-12-05
dp[k][0]表示以k點為根的子樹最小需要的結點數(k不取),同樣,dp[k][1]表示以k點為根的子樹最小需要的結點數(k取),其中,父結點不取,則兒子結點就必取有轉移方程:dp[root][0] = dp[son][1],dp[root][0] = min( dp[son][1],dp[son][0] ) +1,利用dfs回溯進行dp#include <map>#include <set>#include <list>#include
Time of Update: 2018-12-05
雖然是看別人做的,但是有點不明白他那個標記數組vis,因為他標記的是反向邊,而我習慣標記點,因此搞了很久,終於讓我想明白了,如果想要標記點的話,因為是雙向鄰接表,只需要標記分治出來的根節點就行了,然後一層層分治下去,好好體會http://hi.baidu.com/yy17yy/blog/item/865dee006f8663147aec2cee.html#define N 10010struct edge{ int v; int next; int
Time of Update: 2018-12-05
稍後放出解釋。。。int st[66];int cur[66];char str[110][15];int dp[110][66][66];//dp[i][j][k] 表示第i行狀態為j,第i-1狀態為k時的最大炮兵個數int num[66];int n,m;int tot;bool ok(int x){ if(x & (x<<1))return 0; if(x & (x<<2))return 0; return 1;}void
Time of Update: 2018-12-05
這裡需要加上超級源點和超級匯點,分別是n和n+1,然後用EK求最大流,因為EK的複雜度是O(V*E*E),所以時間很慢,網路流還有其他更最佳化的演算法,但暫時不懂,學會了再做一遍比較一下效率。。。這裡的輸入有一點點噁心,用sscanf分離數字和符號EK演算法:625ms#define MIN INT_MIN#define MAX INT_MAX#define N 110int min(int a,int b){return a>b?b:a;}int c[N][N];int f[N][N];
Time of Update: 2018-12-05
#include <map>#include <set>#include <list>#include <queue>#include <deque>#include <stack>#include <string>#include <cstdio>#include <math.h>#include <iomanip>#include