vis

专题训练之双连通

蹲街弑〆低调 提交于 2020-03-29 07:45:11
桥和割点例题+讲解:hihocoder1183 http://hihocoder.com/problemset/problem/1183 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<set> 6 using namespace std; 7 const int maxn=1005; 8 const int maxm=200010; 9 struct edge{ 10 int to,nxt; 11 bool cut; 12 }edge[maxm*2]; 13 int head[maxn],tot; 14 int low[maxn],dfn[maxn]; 15 int index,n,bridge; 16 set<int>st; 17 bool cut[maxn]; 18 19 void addedge(int u,int v) 20 { 21 edge[tot].to=v; 22 edge[tot].nxt=head[u]; 23 edge[tot].cut=false; 24 head[u]=tot++; 25 } 26 27 void tarjan(int u,int pre) 28 { 29 low[u]=dfn[u]=++index; 30

algorithm@ dijkstra algorithm & prim algorithm

不想你离开。 提交于 2020-03-28 14:11:36
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<limits> 5 #include<vector> 6 using namespace std; 7 const int maxn=6; 8 struct edge{ 9 int to,cost; 10 edge(int t,int c){ 11 this->to=t; this->cost=c; 12 } 13 }; 14 void addEdge(vector<edge> &edgelist, vector<vector<int> > &G,int from,int to,int cost){ 15 edge e = edge(to,cost); 16 edgelist.push_back(e); 17 G[from].push_back(edgelist.size()-1); 18 } 19 void addDoubleEdge(vector<edge> &edgelist, vector<vector<int> > &G,int from,int to,int cost){ 20 addEdge(edgelist,G,from,to,cost); 21 addEdge(edgelist,G,to,from,cost); 22 }

最小斯坦纳树

你离开我真会死。 提交于 2020-03-27 12:16:41
最小斯坦纳树 问题描述: 给定一个包含 \(n\) 个结点和 \(m\) 条带权边的无向连通图 \(G=(V,E)\) 。 再给定包含 \(k\) 个结点的点集 \(S\) ,选出 \(G\) 的子图 \(G'=(V',E')\) 使得: \(S\subseteq V'\) \(G′\) 为连通图; \(E′\) 中所有边的权值和最小。 你只需要求出 \(E′\) 中所有边的权值和。 分析: \(dp[i][s]\) 表示 以 i 为根的一棵树,包含集合 S 中所有点的最小代价 \(i\) 号点不一定在 \(s\) 中 \(w[i][j] + dp[j][s] -> dp[i][s]\) \(dp[i][T] + dp[i][S-T] -> dp[i][S]\quad(T \subseteq S)\) 第二类转移可以用枚举子集来转移,第一类转移是一个三角不等式,可以用 \(spfa\) 或者 \(dijkstra\) 第一类转移复杂度为 \(O(m\log m \times 2^k)\) 第二类转移复杂度为 \(O(n\times 3^n)\) ,子集枚举的时间复杂度可以用二项式定理求出 代码: const int N = 100 + 5; const int M = 1010; int n, m, k, x, y, z, tot; int head[N], ver[M], nxt

[CCF CSP]201909-2 小明种苹果(续)

安稳与你 提交于 2020-03-26 13:20:30
模拟题,尝试用python3写了一发,发现不能ac,觉得可能是python写挂了,又用C++写了一遍,还是只能90分。 最后通过看他人的博客被点醒,N=3且3组都有掉落情况时,E=3!! 其实还是自己读题能力弱了,题意中有对第三个统计量的形式化解释: 是满足条件的元素个数。 另外,还需要注意总和数T可能爆int,需要开longlong(python无视) C++代码: #include<bits/stdc++.h> using namespace std; #define ll long long ll n,cnt=0,a; const ll N=1000+5; ll vis[N]; ll D,E,T; int main() { ll n,m; cin>>n; T=D=E=0; for(ll i=1;i<=n;i++) { cin>>m; cin>>a; ll temp=a; for(ll j=2;j<=m;j++) { cin>>a; if(a>0) { if(temp>a&&!vis[i]) { D++; vis[i]=1; } temp=a; } else temp+=a; } T+=temp; if(i>=3&&vis[i-2]&&vis[i-1]&&vis[i])E++; } if(n>=3&&vis[1]&&vis[n-1]&&vis[n]) E++; if(n>=3&

康拓展开和康拓逆展开

*爱你&永不变心* 提交于 2020-03-25 03:28:17
  X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!。这就是康托展开。 ------来自百度百科 上面这句话说了感觉一头雾水,没有任何条件只是给一个式子谁也看不懂那是什么,所以还需要来解释一下。上面的式子可以在求给定一个全排列,求在整个全排列序列中的第几个。 例如:{1,2,3}按从小到大排列一共6个。123 132 213 231 312 321 。如果想知道 3 2 1 在这个排列序列中数第几位这时候需要用到康拓展开了。   第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个大的数。 2*2!+1*1!是康托展开。   再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2 1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数 0*1!

The 2018 ACM-ICPC Asia Beijing Regional Contest

流过昼夜 提交于 2020-03-23 18:43:20
http://hihocoder.com/problemset/problem/ #1870 : Jin Yong’s Wukong Ranking List 我是每加1个点就dfs判断1次。 正解是拓扑排序。。。 1 #include <cstdio> 2 #include <cstdlib> 3 #include <ctime> 4 #include <cstring> 5 #include <string> 6 #include <map> 7 #include <set> 8 #include <list> 9 #include <queue> 10 #include <vector> 11 #include <bitset> 12 #include <algorithm> 13 #include <iostream> 14 using namespace std; 15 const int maxn=50; 16 17 bool vis[maxn]; 18 char str[maxn][maxn],a[maxn],b[maxn],result1[maxn],result2[maxn]; 19 vector<int>e[maxn]; 20 int r; 21 22 void dfs(int d) 23 { 24 vector<int>::iterator j; 25 vis

C. Ehab and Path-etic MEXs(树)

风流意气都作罢 提交于 2020-03-21 05:57:40
题意:给出一颗树,给树的每条边编号(0 - n-2),问使树上两点mex(u,v)最大值最小的编号策略。 解法:根据树的结构,可知找到节点度数大于等于3的点,确定0、1、2. 如果是一条直链则最大值为n-1编号任意。 #include<bits/stdc++.h> using namespace std; typedef long long ll ; #define int ll #define mod 998244353 #define gcd(m,n) __gcd(m, n) #define rep(i , j , n) for(int i = j ; i <= n ; i++) #define red(i , n , j) for(int i = n ; i >= j ; i--) #define ME(x , y) memset(x , y , sizeof(x)) int lcm(int a , int b){return a*b/gcd(a,b);} ll quickpow(ll a , ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;b>>=1,a=a*a%mod;}return ans;} //int euler1(int x){int ans=x;for(int i=2;i*i<=x;i++)if(x%i==0){ans-

图论:点分治

做~自己de王妃 提交于 2020-03-20 20:08:53
点分治我感觉是图论树部分比较考验脑力的一种题目了 POJ1741 题意:给一棵边带权树,问两点之间的距离小于等于K的点对有多少个 满足条件的点对有两种情况:两个点的路径横跨树根,两个点位于同一颗子树中 对于根节点进行一次dfs,求出deep,并将其从小到大排序 void getdeep(int x,int fa) { dep[++dep[0]]=d[x]; for(int tmp=g[x];tmp;tmp=e[tmp].next) { if(e[tmp].t==fa||vis[e[tmp].t]) continue; d[e[tmp].t]=d[x]+e[tmp].v; getdeep(e[tmp].t,x); } } 然后看一下calculate int cal(int x,int tmp) { d[x]=tmp;dep[0]=0; getdeep(x,0); sort(dep+1,dep+dep[0]+1); int t=0,l,r; for(l=1,r=dep[0];l<r;) { if(dep[l]+dep[r]<=k) {t+=r-l;l++;} else r--; } return t; } 如果我们已经知道了此时所有点到根的距离a[i] a[x] + a[y] <= k的(x, y)对数就是结果,这个可以通过排序之后O(n)的复杂度求出 然后根据分治的思想

DFS(深度优先搜索)

假如想象 提交于 2020-03-20 00:03:54
深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。(直到走不下去才往回走) 基本模板 1 int check(参数) 2 { 3 if(满足条件) 4 return 1; 5 return 0; 6 } 7 8 void dfs(int step) 9 { 10 判断边界 11 { 12 相应操作 13 } 14 尝试每一种可能 15 { 16 满足check条件 17 标记 18 继续下一步dfs(step+1) 19 恢复初始状态(回溯的时候要用到) 20 } 21 } 实例 1、全排列(字符串内元素的所有排列方法)(洛谷CF6A与此题类似) 1 //全排列问题 2 #include<stdio.h> 3 #include<string.h> 4 5 int n; 6 char a[15]; 7 char re[15]; 8 int vis[15]; 9 //假设有n个字符要排列,把他们依次放到n个箱子中 10 //先要检查箱子是否为空,手中还有什么字符,把他们放进并标记。 11

图论笔记

不羁的心 提交于 2020-03-19 00:15:21
目录 最小生成树 例题 怎么证明合数都可以分成素数的乘积 在最大生成树上求两点路径中边权的最小值 kruskal重构树 最短路 SPFA判负环 建图技巧 拓扑排序 queue优化 tarjian 差分约束 环套树/基环树 基环树找环 欧拉图 圈套圈算法 图论 最小生成树 \(N\) 个城市, \(M\) 条可修的公路,每条公路有一个修的成本 \(w_i\) ,要使 \(N\) 个城市连通,所需要的最低成本? 最少需要 \(N-1\) 条边,构成一棵树。 ## Kruskal算法证明 对图的顶点数 \(n\) 做归纳,证明 \(Kruskal\) 算法对任意 \(n\) 阶图都适用 归纳基础 \(n=1\) ,显然能找到最小生成树 归纳过程 例题 P1550 [USACO08OCT]打井Watering Hole 思路就是建立一个超级源点往每个点建一条边权为 \(w_i\) 的边,然后跑最小生成树 怎么证明合数都可以分成素数的乘积 就不写了,我太菜了 在最大生成树上求两点路径中边权的最小值 int f[N][20]; //i的第2^j祖先 int mn[N][20]; //i往上跳2^j祖先所经过的边的最小值 int query(int u,int v) { int ans=inf; if(dep[u]>dep[v]) swap(u,v); for(int i=0,k=dep[v]