2020.11.17&18訓練記錄
阿新 • • 發佈:2020-11-18
2020.11.17&18訓練記錄
2020.11.17
CSP考完之後直接AFO了((
yls表示要加強訓練了。。。。
轉回正題:
2020.11.17第一題:BZOJ1123——BLO-Blockade
讀題之後可以很快的分析出題目做法:
1.如果當前被考慮的點i不是整張圖的割點:
那麼i被刪除掉之後其他點心中毫無波瀾,因為跟他們沒有半毛錢關係,而無法互相到達的點對(注意是有序的)就只有其他點和這個犧牲的點(大霧
所以在這種情況下答案就是2*(n-1)
2.如果當前被考慮的點i是整張圖的割點:
那麼這個點的犧牲會導致整個帝國的權利動盪
整張圖會被分成若干個連通塊。我們不妨設第一個連通塊S1的大小是siz1,第二個連通塊S2的大小siz2,以此類推
那麼連通塊與連通塊之間是都不能到達的,所以此時我們的公式為:
siz1(n-siz1)+siz2(n-siz2)+……+sizk*(n-sizk)
注意最好還可能剩下一小部分的點所以也要加上,否則可能會WA
貼程式碼:
//Tarjan 割點 //BLO-Blockade #include<bits/stdc++.h> #define int long long using namespace std; const int AIRBUS_A330_941NX=100010; const int AIRBUS_A330_841NX=500010; int dfn[AIRBUS_A330_941NX],low[AIRBUS_A330_941NX],iscut[AIRBUS_A330_941NX]; int tot,ver[AIRBUS_A330_841NX<<1],head[AIRBUS_A330_841NX],nxt[AIRBUS_A330_841NX<<1]; int n,m; int siz[AIRBUS_A330_941NX],ans[AIRBUS_A330_941NX]; int num; int read() { int x=0,f=1; char c=getchar(); while (c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while (c>='0'&&c<='9') { x=(x<<1)+(x<<3)+(c^48); c=getchar(); } return x*f; } void addedge(int x,int y) { tot++; ver[tot]=y; nxt[tot]=head[x]; head[x]=tot; } void Tarjan(int p) { num++; dfn[p]=low[p]=num; // iscut[p]=false; siz[p]=1; int flag=0,sum=0; for(int i=head[p];i;i=nxt[i]) { int q=ver[i]; if(!dfn[q]) { Tarjan(q); siz[p]+=siz[q]; low[p]=min(low[p],low[q]); if(low[q]>=dfn[p]) { flag++; ans[p]+=siz[q]*(n-siz[q]); sum+=siz[q]; if(flag>1 || p!=1) iscut[p]=true; } } else low[p]=min(low[p],dfn[q]); } if(iscut[p]) ans[p]+=(sum+1)*(n-sum-1)+n-1; else ans[p]=2*n-2; } signed main() { n=read(),m=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); addedge(x,y); addedge(y,x); } Tarjan(1); //for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); for(int i=1;i<=n;i++) printf("%lld\n",ans[i]); return 0; }
2020.11.17第二題:BZOJ2657——旅遊
讀題之後可以很快的分析出題目做法:
因為是三角形,所以這些三角形之間肯定有一些公共邊。
用這些公共邊來重新建圖,此時的樹的直徑即為所求的結果。
2020.11.18第一題:BZOJ1143——祭祀river
讀題之後可以很快的分析出題目做法:
本題要求的答案的定義其實與二分圖最大獨立集非常像,而題目中又有可能將圖分成2個點集,所以我們嘗試使用二分圖來做。
因為這些點不一定聯通所以我們要先Floyd傳遞閉包一下,之後再使用Hungary演算法來計算二分圖最大匹配數,由此計算出二分圖最大獨立集也就是此題的答案。
貼程式碼:
#include<bits/stdc++.h> using namespace std; const int N=1010; const int M=1010; int match[N],tot; bool use[N]; int n,m,ans; int g[N][N]; int read() { int x=0,f=1; char c=getchar(); while (c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while (c>='0'&&c<='9') { x=(x<<1)+(x<<3)+(c^48); c=getchar(); } return x*f; } bool DFS(int x) { for(int i=1;i<=n;i++) { if(!use[i] && g[x][i]) { use[i]=true; if(!match[i] || DFS(match[i])) { match[i]=x; return true; } } } return false; } void hungary() { tot=0; for(int i=1;i<=n;i++) { memset(use,0,sizeof(use)); ans-=DFS(i); } } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); g[x][y]=1; } for(int i=1;i<=n;i++) g[i][i]=1; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) g[i][j]|=g[i][k]&g[k][j]; for(int i=1;i<=n;i++) g[i][i]=0; ans=n; hungary(); printf("%d\n",ans); return 0; }