【SinGuLaRiTy-1041】 Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.

计算树的直径

//方法:任选一个点作为起点进行一次BFS,找到最远点u。再以u为起点做一次BFS,找最长路即直径。
queue<int>point;
void bfs(int a,int dis[])
{
memset(dis,inf,sizeof dis);
dis[a]=;
point.push(a);
int v ,u ;
while(!point.empty())
{
u=point.front();
point.pop();
for(node *p=adj[u];p!=NULL;p=p->next)
if(dis[(v=p->v)]>dis[u]+p->w)
{
dis[v]=dis[u]+p->w;
point.push(v);
}
}
} void solve()//输出直径长度
{
bfs(,dis);
int flag=;
for(int i=;i<=n;++i)
if(dis[flag]<dis[i])
flag=i;
bfs(flag,dis2);
int flag2=;
for(int i=;i<=n;++i)
if(dis2[flag2]<dis2[i])
flag2=i;
printf("%d",dis2[flag2]);
}

LCA-返回a,b两点间的最短边权

返回a,b两点之间的最短边权
void dfs(int u)
{
int v ;
for(node *p=adj[u];p!=NULL;p=p->next)
{
v=p->v;
f[v][]=u ;
dep[v]=dep[u]+ ;
dfs(v);
}
} void init()
{
dep[root]= ;
dfs(root);
f[root][]=root ;
for(int j=;j<MAXK;++j)
for(int i=;i<=n;++i)
f[i][j]=f[f[i][j-]][j-];
} void adjust(int &u,int val)
{
for(int j=MAXK-;j>=;--j)
if(dep[f[u][j]]>=val)
u=f[u][j];
} int solve(int u,int v)
{
if(dep[u]>dep[v])adjust(u,dep[v]);
else if(dep[u]<dep[v])adjust(v,dep[u]);
if(u==v)return u;
for(int j=MAXK-;j>=;--j)
if(f[u][j]!=f[v][j])
u=f[u][j] ,v=f[v][j];
return f[u][];
}

LCA 最近公共祖先-在线倍增

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std; const int N=,L=;
int m,first[N],next[N],d[N],f[N][L];
inline void dfs(int x,int dep)
{
d[x]=dep;
m=max(m,dep);
for (int i=first[x];i;i=next[i]) dfs(i,dep+);
}
int log2(int x)
{
int k=;
while (x>)
{
x>>=;
k++;
}
return k;
}
int main()
{
int i,j,n,s,x,y,root;
scanf("%d",&n);
for (i=;i<=n;i++)
{
scanf("%d",&f[i][]);
if (!f[i][]) root=i;
next[i]=first[f[i][]];
first[f[i][]]=i;
}
dfs(root,);
s=log2(m);
for (j=;j<=s;j++)
for (i=;i<=n;i++) f[i][j]=f[f[i][j-]][j-];
scanf("%d",&n);
while (n--)
{
scanf("%d%d",&x,&y);
if (d[x]<d[y]) swap(x,y);
s=log2(d[x]-d[y]);
while (d[x]>d[y])
{
if (d[x]-(<<s)>=d[y]) x=f[x][s];
s--;
}
s=log2(d[x]);
while (s>-)
{
if (f[x][s]!=f[y][s])
{
x=f[x][s];
y=f[y][s];
}
s--;
}
printf("%d\n",x==y?x:f[x][]);
}
return ;
}

LCA 最近公共祖先-树链(双链树存图)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define N 100001
using namespace std; int a[N*],d[N],down[N],next[N],top,f[*N][],loc[*N][],n,b[N];
int log2(int x)
{
int k=;
while (x>)
{
x/=;
k++;
}
return k;
}
void dfs(int x,int dep)
{
int i;
d[x]=dep;
a[++top]=x;
for (i=down[x];i!=;i=next[i])
{
dfs(i,dep+);
a[++top]=x;
}
}
void init()
{
int i,j,s,x,k;
for (i=;i<=top;i++)
{
f[i][]=d[a[i]];
loc[i][]=a[i];
}
s=log2(top);
for (j=;j<=s;j++)
{
k=top-(<<j)+;
for (i=;i<=k;i++)
{
x=i+(<<(j-));
if (f[i][j-]<=f[x][j-])
{
f[i][j]=f[i][j-];
loc[i][j]=loc[i][j-];
}
else
{
f[i][j]=f[x][j-];
loc[i][j]=loc[x][j-];
}
}
}
}
int main()
{
int i,k,x,y,t;
scanf("%d",&n);
for (i=;i<=n;i++) down[i]=d[i]=next[i]=;
for (i=;i<=n;i++)
{
scanf("%d",&x);
next[i]=down[x];
down[x]=i;
}
top=;
dfs(down[],);
for (i=;i<=top;i++) if (b[a[i]]==) b[a[i]]=i;
init();
scanf("%d",&t);
while (t>)
{
t--;
scanf("%d%d",&x,&y);
x=b[x];
y=b[y];
if (x>y) swap(x,y);
i=log2(y-x);
k=y-(<<i)+;
printf("%d\n",f[x][i]<f[k][i]?loc[x][i]:loc[k][i]);
}
return ;
}

LCA 最近公共祖先-tarjan算法

void tarjan(int u)
{
for(node *p=adj[u];p!=NULL;p=p->next)
{
tarjan(p->v);
Union(p->v,u);
}
vis[u]=; for(int i=;i<=ask[u][];++i)
if(vis[ask[u][i]]==)
printf("%d\n",getroot(ask[u][i]));
} void init()
{
scanf("%d",&m);
while(m--)
{
scanf("%d%d",&a,&b);
ask[a][++ask[a][]]=b;
ask[b][++ask[b][]]=a;
}
for(int i=;i<=n;++i)
if(!in[i])
{
tarjan(i);
break;
}
}

前向星存图

struct node
{
int v ,w ;
node *next ;
}edge[MAXM<<1] ,*adj[MAXN] ,*code=edge ; void add(int a,int b,int c)
{
++code;
code->v=b ,code->w=c ,code->next=adj[a] ;
adj[a]=code ;
}

最短路-Dijkstra

#define inf 0x3f3f3f3f
int dis[MAXN+5] ;
bool flag[MAXN+5] ;
void dijkstra(int a)
{
memset(dis,inf,sizeof dis);
dis[a]=0;
int minv ;
for(int i=1;i<=n;++i)
{
minv=0 ;
for(int i=1;i<=n;++i)
if(!flag[i]&&dis[minv]>dis[i])
minv=i;
if(minv==0)break;
flag[minv]=1;
for(node *p=adj[minv];p!=NULL;p=p->next)
dis[p->v]=min(dis[p->v],dis[minv]+p->w);
}
}

最短路-优先队列(堆优化的Dijkstra)

struct node
{
int v ,w ;
node *next ;
bool operator < (const node &a) const
{
return w>a.w;
}
}edge[MAXM<<1] ,*adj[MAXN] ,*code=edge ;
priority_queue<node, vector<node> > q;//注意必须开结构体,因为若在队列中一个元素的dis发生改变,队列不会对它重新排序 void dijkstra(int a)
{
memset(vis,0,sizeof vis);
memset(dis,inf,sizeof dis);
dis[a]=0 ;
q.push((node){a,0});
int u ,d ,v ;
while(!q.empty())
{
u=q.top().v ,d=q.top().w ;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(node *p=adj[u];p!=NULL;p=p->next)
if(!vis[(v=p->v)]&&dis[v]>dis[u]+p->w)
{
dis[v]=dis[u]+p->w;
q.push((node){v,dis[v]});
}
}
}

最短路-SPFA+判断负权环路

#define inf 0x3f3f3f3f
queue<int>point;
int dis[MAXN+5] ,vis[MAXN+5] ;
bool in[MAXN+5] ;
void spfa(int a)
{
int u ,v ;
memset(dis,inf,sizeof dis);
point.push(a);
dis[a]=0 ,in[a]=vis[a]=1 ;
while(!point.empty())
{
u=point.front();
in[u]=0 ;
point.pop();
for(node *p=adj[u];p!=NULL;p=p->next)
if(dis[(v=p->v)]>dis[u]+p->w)
{
dis[v]=dis[u]+p->w;
if(!in[v])
{
in[v]=1;
point.push(v);
if(++vis[v]>n)
{
puts("No Solution");
return;
}
}
}
}
}

最短路-Floyd

int dis[MAXN+5][MAXN+5] ;
void floyd()
{
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
if(k!=i)
for(int j=1;j<=n;++j)
if(i!=j&&k!=j)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}

一笔画问题-欧拉回路

#include <iostream>
#include <cstdio>
#define MAXN 105
using namespace std; int n ,m ,a ,b ,map[MAXN+5][MAXN+5] ,temp[MAXN<<1] ,du[MAXN] ,cnt ;
int flag[5] ,pos ; void dfs(int u)
{
for(int v=1;v<=n;++v)
if(map[u][v])
{
map[u][v]=map[v][u]=0;
dfs(v);
}
temp[++cnt]=u ;
} int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
scanf("%d",&map[i][j]);
if(map[i][j])++du[i];
}
for(int i=1;i<=n;++i)
if(du[i]&1)
flag[++pos]=i ;
if(pos!=0&&pos!=2)
{
puts("No Solution!");
return 0;
}
if(pos==0)flag[1]=flag[2]=1;
dfs(flag[1]); for(int i=cnt;i>1;--i)
printf("%d ",temp[i]);
printf("%d\n",temp[1]);
return 0;
}

多叉树(森林)转二叉树

//输入N,M表示节点数和边数,再输入M组边关系,从1到N输出每个结点的父亲,根节点父亲为0
#include<cstdio>
#include<algorithm>
using namespace std;
void read(int &x)
{
int f=;x=;char s=getchar();
while(s<''||s>''){if(s=='-')f=-;s=getchar();}
while(s>=''&&s<=''){x=x*+s-'';s=getchar();}
x*=f;
}
#define MAXN 100
struct node
{
int l,r,f;
}tree[MAXN+];
int N,M;
int root[MAXN+],rs;
bool d[MAXN+][MAXN+];
void rtb()//处理森林
{
for(int i=;i<=N;i++)
if(!tree[i].f)
root[++rs]=i;
for(int i=rs;i>;i--)
{
tree[root[i-]].r=root[i];
tree[root[i]].f=root[i-];
}
}
int main()
{
read(N),read(M);
for(int i=;i<=M;i++)
{
int x,y;
read(x),read(y);
d[x][y]=;//先保存起来
}
for(int i=;i<=N;i++)//再处理
for(int j=;j<=N;j++)
if(d[i][j])
{
if(tree[i].l==)
{
tree[i].l=j;
tree[j].f=i;
}
else
{
int t=tree[i].l;
while(tree[t].r) t=tree[t].r;
tree[t].r=j;
tree[j].f=t;
}
}
rtb();
for(int i=;i<=N;i++)
{
if(i<N) printf("%d\n",tree[i].f);
else printf("%d",tree[i].f);
}
}

树的先序,中序,后序遍历-非递归版

//先序遍历
void PreOrder(Node* root) {
assert(NULL != root)
stack<Node*> store;
store.push(root); // 根结点入栈
while(!store.empty()) {
root = store.top(); // 在循环中,root记录的是当前准备输出的结点
store.pop();
cout << root->value << " "; // 输出当前结点
if(root->right_child) // 右孩子入栈
store.push(root->right_child);
if(root->left_child) // 左孩子入栈
store.push(root->left_child);
}
} //中序遍历
void InOrder(Node* root) {
assert(NULL != root);
stack<Node*> store;
while(root && !store.empty()) {
if(root != NULL) { // 只要不为空,就一路向左结点方向走去
store.push(root);
root = root->left_child;
}
else { // store.top()的左边都走过了
cout << store.top()->value << " "; // 输出当前结点
root = store.top()->right_child;
store.pop();
}
}
} //后序遍历
void PostOrder(Node* root) {
assert(NULL != root);
Node* Pre = NULL;
stack<Node*> store;
while(root && !store.empty()) {
if(root != NULL) { // 一路向左
store.push(root);
root = root->left_child;
}
else { // stack.top()的左子树都输出完了
if(store.top()->right_child!=NULL && store.top()->right_child!=Pre) {
// 右子树存在且没有输出过
root = root->right_child;
}
else { // 左右子树都输出过了
cout << store.top()->value << " ";
Pre = store.top();
store.pop();
}
}
}
}

树的先序,中序,后序遍历-递归版

//先序遍历
void preOrder1(BinTree *root)
{
if(root!=NULL)
{
cout<<root->data<<" ";
preOrder1(root->lchild);
preOrder1(root->rchild);
}
} //中序遍历
void inOrder1(BinTree *root)
{
if(root!=NULL)
{
inOrder1(root->lchild);
cout<<root->data<<" ";
inOrder1(root->rchild);
}
} //后序遍历
void postOrder1(BinTree *root)
{
if(root!=NULL)
{
postOrder1(root->lchild);
postOrder1(root->rchild);
cout<<root->data<<" ";
}
}

求树的重心

//以 POJ 1655 为例
//题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的.
#include<iostream>
#include<cstring>
#include<cstdio> using namespace std;
const int N = ;
const int INF = <<; int head[N];
int son[N];
bool vis[N];
int cnt,n;
int ans,size; struct Edge
{
int to;
int next;
}; Edge edge[*N]; void Init()
{
cnt = ;
size = INF;
memset(vis,,sizeof(vis));
memset(head,-,sizeof(head));
} void add(int u,int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
} void dfs(int cur)
{
vis[cur] = ;
son[cur] = ;
int tmp = ;
for(int i=head[cur];~i;i=edge[i].next)
{
int u = edge[i].to;
if(!vis[u])
{
dfs(u);
son[cur] += son[u] + ;
tmp = max(tmp,son[u] + );
}
}
tmp = max(tmp,n-son[cur]-);
if(tmp < size || tmp == size && cur < ans)
{
ans = cur;
size = tmp;
}
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
Init();
scanf("%d",&n);
for(int i=;i<=n-;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs();
printf("%d %d\n",ans,size);
}
return ;
}

最小生成树-Kruskal

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1010, MAXM = 100010;
int N, M; struct Edge {
int a, b, d;
bool operator < (const Edge&t) const {
return d < t.d;
}
} ed[MAXM]; int tfa[MAXN];
void init() {
for (int i = 1; i<=N; ++i)
tfa[i] = i;
}
int root(int x) {
if (x == tfa[x]) return x;
return tfa[x] = root(tfa[x]);
}
void unite(int x, int y) {
tfa[root(x)] = root(y);
} int Kruskal()
{
sort(ed+1, ed+M+1);
int i, cnt = 0, a, b, ans = 0;
for (i = 1; i<=M && cnt<M-1; ++i) {
a = ed[i].a;
b = ed[i].b;
if (root(a) != root(b))
unite(a, b), cnt++, ans += ed[i].d;
}
return ans;
} int main()
{
init(); printf("%d", Kruskal());
return 0;
}

最小生成树-Prim

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int MAXN = 5010, MAXM = 500010;
const int INF = 0x3f3f3f3f;
int N, M; struct Node {
int to, d;
Node *next;
}Edge[MAXM*2], *ecnt=Edge, *adj[MAXN];
void addedge(int a, int b, int c)
{
(++ecnt)->to = b;
ecnt->d = c;
ecnt->next = adj[a];
adj[a] = ecnt;
} bool vis[MAXN];
struct Near {
int to, d;
Near(){}
Near(int a,int b){to=a;d=b;}
bool operator < (const Near&t) const {
return d > t.d;
}
};
int prim()
{
int cnt = 0, ans = 0;
priority_queue<Near> Q;
Q.push(Near(1, 0));
while (cnt < N && !Q.empty())
{
int u = Q.top().to, d = Q.top().d;
Q.pop();
if (vis[u]) continue;
ans += d;
vis[u] = 1;
++cnt;
for (Node*p = adj[u]; p; p=p->next)
if (!vis[p->to])
Q.push(Near(p->to, p->d));
}
return ans;
} int main()
{ return 0;
}

拓扑排序-Toposort

int ans[MAXN+5] ;
bool vis[MAXN+5] ;
void topo()
{
int flag ;
for(int i=1;i<=n;++i)
{
flag=0;
for(int j=1;j<=n;++j)
if(!vis[j]&&!in[j])
{flag=j;break;}
if(!flag)
{
puts("no solution");
return;
}
ans[i]=flag ,vis[flag]=1 ;
for(node *p=adj[flag];p!=NULL;p=p->next)
--in[p->v];
}
for(int i=1;i<n;++i)
printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}

求割点

int low[MAXN] ,dfn[MAXN] ,cnt ,root_son ;
bool cutp[MAXN] ;
void dfs(int u,int fa)
{
int v ;
low[u]=dfn[u]=++cnt ;
for(node *p=adj[u];p!=NULL;p=p->next)
{
v=p->v;
if(!dfn[v])
{
dfs(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])//在这里注意打上{}
{
if(fa!=-1)cutp[u]=1 ;
else ++root_son;
}
}
else if(v!=fa)
low[u]=min(low[u],dfn[v]);
}
} void tarjon()
{
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
cnt=0;
for(int i=1;i<=n;++i)
if(!dfn[i])
{
root_son=0 ;
dfs(i,-1);
cutp[i]=root_son-1 ;
}
}

求割边(即桥)

int low[MAXN] ,dfn[MAXN] ,cnt ,root_son ;
int cnte[MAXM][2] ,pos ;
void dfs(int u,int fa)
{
int v ;
low[u]=dfn[u]=++cnt ;
for(node *p=adj[u];p!=NULL;p=p->next)
{
v=p->v;
if(!dfn[v])
{
dfs(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])
cnte[++pos][0]=u ,cnte[pos][1]=v ;
}
else if(v!=fa)
low[u]=min(low[u],dfn[v]);
}
} void tarjon()
{
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
cnt=0;
for(int i=1;i<=n;++i)
if(!dfn[i])
dfs(i,-1);
}

双联通分量

stack< pair<int,int> >e;
pair<int,int>tmp ;
int dfn[MAXN] ,low[MAXN] ,cnt ,pos ;
void dfs(int u,int fa)
{
low[u]=dfn[u]=++cnt ;
int v ;
for(node *p=adj[u];p!=NULL;p=p->next)
{
v=p->v;
if(!dfn[v])
{
e.push(make_pair(u,v));
dfs(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
printf("Block No. %d\n",++pos);
do
{
tmp=e.top();
e.pop();
printf("%d, %d\n",tmp.first,tmp.second);
}while(tmp.first!=u||tmp.second!=v);
}
}
else if(v!=fa)
{
low[u]=min(low[u],dfn[v]);
if(dfn[u]>low[v])
e.push(make_pair(u,v));
}
}
} void tarjon()
{
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
cnt=0;
for(int i=1;i<=n;++i)
if(!dfn[i])
dfs(i,-1);
}

有向图强连通分量

int cnt ,pos ,low[MAXN+5] ,dfn[MAXN+5] ,block[MAXN+5] ;
void dfs(int u)
{
int v ;
low[u]=dfn[u]=++cnt;
in[u]=1 ;
stack[++tail]=u;
for(node *p=adj[u];p!=NULL;p=p->next)
{
v=p->v;
if(!dfn[v])
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(in[v])
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
++pos;
do
{
block[stack[tail]]=pos;
in[stack[tail]]=0;//忘记删除标记- -
--tail;
}while(stack[tail+1]!=u);
}
} void tarjon()
{
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
cnt=pos=0;
for(int i=1;i<=n;++i)
if(!dfn[i])
dfs(i);
}

二分图判定-DFS

//以 HDU 2444 为例
//题意:给出一个无向图,若为二分图则求最大匹配,否则输出"No"。
#include<iostream>
#include<cstring>
#include<cstdio> using namespace std;
const int N = ; int head[N],link[N];
bool vis[N],col[N];
int cnt,n,m; struct Edge
{
int to;
int next;
}; Edge edge[N*N]; void Init()
{
cnt = ;
memset(head,-,sizeof(head));
memset(col,,sizeof(col));
} void add(int u,int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
} bool Color(int u)
{
for(int i=head[u]; ~i; i=edge[i].next)
{
int v = edge[i].to;
if(!col[v])
{
col[v] = !col[u];
if(!Color(v)) return false;
}
else if(col[v] == col[u])
return false;
}
return true;
} bool dfs(int u)
{
for(int i=head[u]; ~i; i=edge[i].next)
{
int v = edge[i].to;
if(!vis[v])
{
vis[v] = ;
if(link[v] == - || dfs(link[v]))
{
link[v] = u;
return true;
}
}
}
return false;
} int match()
{
int ans = ;
memset(link,-,sizeof(link));
for(int i=; i<=n; i++)
{
memset(vis,,sizeof(vis));
if(dfs(i)) ans++;
}
return ans;
} int main()
{
while(~scanf("%d%d",&n,&m))
{
if(n == )
{
puts("No");
continue;
}
Init();
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
col[] = ;
if(!Color())
{
puts("No");
continue;
}
printf("%d\n",match()>>);
}
return ;
}

二分图最大匹配-匈牙利算法

bool dfs(int u)
{
for(int v=1;v<=cntx;++v)
if(!vis[v]&&map[u][v])
{
vis[v]=1;
if(!cy[v]||dis(cy[v]))
{
cx[u]=v ,cy[v]=u ;
return 1;
}
}
return 0;
} int match()
{
memset(cx,0,sizeof cx);
memset(cy,0,sizeof cy);
int ans=0;
for(int i=1;i<=cntx;++i)
if(!cx[i])
{
memset(vis,0,sizeof vis);
ans+=dfs(i);
}
return ans;
}

二分图最佳匹配-KM算法

const int inf=1e9,maxn=;
int KM(int m,int n,int tu[][maxn],int *match1,int *match2)
{
int s[maxn],t[maxn],l1[maxn],l2[maxn],p,q,ret=,i,j,k;
///l1为左边的匹配分量,l2是右边的匹配分量
for(i=; i<m; i++)
{
for(l1[i]=-inf,j=; j<n; j++)
l1[i]=tu[i][j]>l1[i]?tu[i][j]:l1[i];
if(l1[i]==-inf)
return -;
}
for(i=; i<n; l2[i++]=);
memset(match1,-,sizeof(int)*n);
memset(match2,-,sizeof(int)*n);
for(i=; i<m; i++)
{
memset(t,-,sizeof(int)*n);
for(s[p=q=]=i; p<=q&&match1[i]<; p++)
{
for(k=s[p],j=; j<n&&match1[i]<; j++)
if(l1[k]+l2[j]==tu[k][j]&&t[j]<)
{
s[++q]=match2[j],t[j]=k;
if(s[q]<)
for(p=j; p>=; j=p)
match2[j]=k=t[j],p=match1[k],match1[k]=j;
}
}
if(match1[i]<)
{
for(i--,p=inf,k=; k<=q; k++)
for(j=; j<n; j++)
if(t[j]<&&l1[s[k]]+l2[j]-tu[s[k]][j]<p)
p=l1[s[k]]+l2[j]-tu[s[k]][j];
for(j=; j<n; l2[j]+=t[j]<?:p,j++);
for(k=; k<=q; l1[s[k++]]-=p);
}
}
for(i=; i<m; i++)
ret+=tu[i][match1[i]];
return ret;
}

网络流-SAP

//以HDU 3549为例
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std; typedef struct {int v,next,val;} edge;
const int MAXN=;
const int MAXM=; edge e[MAXM];
int p[MAXN],eid; inline void init(){memset(p,-,sizeof(p));eid=;} //有向
inline void insert1(int from,int to,int val)
{
e[eid].v=to;
e[eid].val=val;
e[eid].next=p[from];
p[from]=eid++; swap(from,to); e[eid].v=to;
e[eid].val=;
e[eid].next=p[from];
p[from]=eid++;
} //无向
inline void insert2(int from,int to,int val)
{
e[eid].v=to;
e[eid].val=val;
e[eid].next=p[from];
p[from]=eid++; swap(from,to); e[eid].v=to;
e[eid].val=val;
e[eid].next=p[from];
p[from]=eid++;
} int n,m;//n为点数 m为边数
int h[MAXN];
int gap[MAXN]; int source,sink;
inline int dfs(int pos,int cost)
{
if (pos==sink)
{
return cost;
} int j,minh=n-,lv=cost,d; for (j=p[pos];j!=-;j=e[j].next)
{
int v=e[j].v,val=e[j].val;
if(val>)
{
if (h[v]+==h[pos])
{
if (lv<e[j].val) d=lv;
else d=e[j].val; d=dfs(v,d);
e[j].val-=d;
e[j^].val+=d;
lv-=d;
if (h[source]>=n) return cost-lv;
if (lv==) break;
} if (h[v]<minh) minh=h[v];
}
} if (lv==cost)
{
--gap[h[pos]];
if (gap[h[pos]]==) h[source]=n;
h[pos]=minh+;
++gap[h[pos]];
} return cost-lv; } int sap(int st,int ed)
{ source=st;
sink=ed;
int ret=;
memset(gap,,sizeof(gap));
memset(h,,sizeof(h)); gap[st]=n; while (h[st]<n)
{
ret+=dfs(st,INT_MAX);
} return ret;
} int main()
{
int t,add=;
scanf("%d",&t);
while(t--)
{
printf("Case %d: ",add++); scanf("%d%d",&n,&m);
init();
int i; int ll,rr,cap;
for(i=;i<m;i++)
{
scanf("%d%d%d",&ll,&rr,&cap);
insert1(ll,rr,cap);
}
printf("%d\n",sap(,n));
}
return ;
}

最大流-ISAP

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define Min(a,b) ((a)<(b)?(a):(b))
#define clear(a) memset(a,0,sizeof a)
const int MAXN = 1010, MAXM = 10010;
const int INF = 1<<29; struct Node {
int to, c;
Node*next, *back;
};
struct FlowNet {
int S, T, vn;
int d[MAXN], vd[MAXN];
Node Edge[MAXM], *ecnt, *adj[MAXN];
FlowNet() { ecnt=Edge; }
void init(int a, int b, int c) {
S = a; T = b; vn = c;
}
void addedge(int a, int b, int c) {
(++ecnt)->to = b; ecnt->c = c;
ecnt->next = adj[a]; adj[a] = ecnt;
ecnt->back = ecnt+1;
(++ecnt)->to = a; ecnt->c = 0;
ecnt->next = adj[b]; adj[b] = ecnt;
ecnt->back = ecnt-1;
}
int aug(int u, int augco)
{
if (u == T) return augco;
int augc = augco, mind = vn-1, delta;
for (Node*p = adj[u]; p; p=p->next)
if (p->c > 0) {
if (d[u] == d[p->to]+1) {
delta = aug(p->to, Min(p->c, augc));
augc -= delta;
p->c -= delta;
p->back->c += delta;
if (d[S]>=vn) return augco-augc;
if (!augc) break;
}
mind = Min(mind, d[p->to]);
}
if (augc == augco) {
if (!--vd[d[u]]) d[S] = vn;
++vd[d[u] = mind+1];
}
return augco - augc;
}
int ISAP()
{
int flow = 0;
clear(d); clear(vd);
vd[0] = vn;
while (d[S] < vn) flow+=aug(1, INF);
return flow;
}
} G; int N, M;
int main()
{
int a, b, c;
scanf("%d%d", &M, &N);
G.init(1, N, N);
for (int i = 1; i<=M; ++i)
{
scanf("%d%d%d", &a, &b, &c);
G.addedge(a, b, c);
}
printf("%d\n", G.ISAP());
return 0;
}

第K短路-K-th_Short

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAXM 100005
#define MAXN 1005
const int INF = 1<<28;
int N, M, S, T, K; struct Node {
int to, len; Node *next;
}Edge[MAXM*4], *ecnt = Edge, *adj[MAXN], *radj[MAXN];
void addedge(int a, int b, int c)
{
++ecnt;
ecnt->to = b;
ecnt->len = c;
ecnt->next = adj[a];
adj[a] = ecnt;
++ecnt;
ecnt->to = a;
ecnt->len = c;
ecnt->next = radj[b];
radj[b] = ecnt;
} struct dijs {
int u, dis;
dijs () {}
dijs (int a,int b) {u=a; dis=b;}
bool operator < (const dijs&a) const {
return dis > a.dis;
}
};
int rdis[MAXN];
bool vis[MAXN];
priority_queue<dijs> dij;
void rDijkstra() //边反向跑最短路以获取H函数值
{
memset(rdis, 0x3f, sizeof rdis);
rdis[T] = 0;
dij.push(dijs(T, 0));
dijs t;
while (!dij.empty()) {
t = dij.top(); dij.pop();
if (vis[t.u]) continue;
vis[t.u] = 1;
for (Node *p = radj[t.u]; p; p=p->next)
if (rdis[p->to] > t.dis + p->len) {
rdis[p->to] = t.dis + p->len;
dij.push(dijs(p->to, rdis[p->to]));
}
}
} struct ss {
int u, pre;
ss () {}
ss (int a, int b) { u=a; pre=b; }
bool operator < (const ss&a) const {
return pre+rdis[u] > a.pre+rdis[a.u]; //pre是G函数值,rdis是H函数值,根据两个之和判定优先级。
}
};
int Tvisn; //第几次到达T点
priority_queue<ss> as;
int Astar()
{
if (S==T) Tvisn = -1; //如果起点终点相等,一开始不算到达终点
as.push(ss(S, 0));
ss t;
while (!as.empty()) {
t = as.top();
as.pop();
if (t.u == T) {
++Tvisn;
if (Tvisn == K) return t.pre; //根据A*算法的正确性,第K次到达即为第K短路
}
for (Node *p = adj[t.u]; p; p=p->next)
as.push(ss(p->to, t.pre + p->len));
}
return -1;
} int main()
{
int i, a, b, c;
scanf("%d%d", &N, &M);
for (i = 1; i<=M; ++i)
{
scanf("%d%d%d", &a, &b, &c);
addedge(a, b, c);
}
scanf("%d%d%d", &S, &T, &K);
rDijkstra();
printf("%d\n", Astar());
return 0;
}

Time: 2017-10-16

[SinGuLaRiTy] 复习模板-图论的更多相关文章

  1. [SinGuLaRiTy] 复习模板-数学

    [SinGuLaRiTy-1047] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 质因数分解 void solve(int n) { == ...

  2. [SinGuLaRiTy] 复习模板-数据结构

    [SinGuLaRiTy-1040] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 二维线段树 2D_Segment_Tree //示例:单 ...

  3. [SinGuLaRiTy] 复习模板-搜索

    [SinGuLaRiTy-1043] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 桶排序 void bucketSort(int a[], ...

  4. [SinGuLaRiTy] 复习模板-高精度模板

    [SinGuLaRiTy-1042] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 结构体封装 //高精度运算 注意%I64d与%lld # ...

  5. django上课笔记4-复习数据库操作-复习模板-Seccion-详细cookie和session的区别

    一.复习数据库操作 字段类型 字符串 EmailField(CharField): IPAddressField(Field) URLField(CharField) SlugField(CharFi ...

  6. NOIP专题复习3 图论-强连通分量

    目录 一.知识概述 二.典型例题 1.[HAOI2006]受欢迎的牛 2.校园网络[[USACO]Network of Schools加强版] 三.算法分析 (一)Tarjan算法 (二)解决问题 四 ...

  7. NOIP专题复习1 图论-最短路

    一.知识概述 今天我们要复习的内容是图论中的最短路算法,我们在这里讲3种最短路求法,分别是:floyd,dijkstra,spfa. 那么我们从几道例题来切入今天讲解的算法. 二.典型例题 1.热浪 ...

  8. NOIP专题复习2 图论-生成树

    目录 一.知识概述 二.典型例题 1.口袋的天空 三.算法分析 (一)Prim算法 (二)Kruskal 四.算法应用 1.[NOIP2013]货车运输 五.算法拓展 1977: [BeiJing20 ...

  9. noip复习模板

    我只会这么多 tarjan:codevs 1332 void tarjan(int u) { dfn[u]=low[u]=Time++; s.push(u); for(int i=head[u];~i ...

随机推荐

  1. ubuntu16.04编译安装php7.2

    1,下载解压 tar xf php-7.2.0.tar.gz cd php-7.2.0/ 2,安装必要的库 sudo apt-get install libxml2-devsudo apt-get i ...

  2. 6.前端基于react,后端基于.net core2.0的开发之路(6) 服务端渲染(SSR)

    0.源码地址 https://gitee.com/teambp/ScaffoldClient  这个地址下载对应源码. 1.服务端渲染是啥? 就是在服务器进行页面渲染(废话),当页面展示后,显示的就是 ...

  3. angular4.0配置本机IP访问项目

    一.查看本机IP 命令行输入 ipconfig,在面板中选择IPv4地址 二.在项目中配置IP 打开package.json文件,修改如下 三.命令行运行 npm start 四.在手机上访问 192 ...

  4. http协议【转】

    HTTP协议详解 当今web程序的开发技术真是百家争鸣,ASP.NET, PHP, JSP,Perl, AJAX 等等. 无论Web技术在未来如何发展,理解Web程序之间通信的基本协议相当重要, 因为 ...

  5. Android查缺补漏(View篇)--自定义View利器Canvas和Paint详解

    上篇文章介绍了自定义View的创建流程,从宏观上给出了一个自定义View的创建步骤,本篇是上一篇文章的延续,介绍了自定义View中两个必不可少的工具Canvas和Paint,从细节上更进一步的讲解自定 ...

  6. 希尔排序(Go语言)

    func ShellSort(num []int) { //increment相隔数量 ;increment> ;increment/= { //i序号较大的数组下标,i ,j进行比较 for ...

  7. PHP开发工程师应该具备那些技术能力

    根据各大招聘网站的数据分析,2017年IT行业,其中从事软件开发和数据分析的毕业生的月薪最高.究其原因是因为随着互联网的不断发展,岗位人才稀缺,需求量大.那么如何快速的成为软件开发人员,比如PHP开发 ...

  8. Linux audio驱动模型

    linux驱动 alsa模型: Linux ALSA声卡驱动之一:ALSA架构简介 Linux ALSA声卡驱动之二:声卡的创建 Linux ALSA声卡驱动之三:PCM设备的创建 Linux ALS ...

  9. 关于Gson定制的分析

    首先,为什么需要定制呢?很多同学可能觉得默认的不也挺好的嘛?最开始,我也是觉得的,而且我们一开始也是用默认的解析方式的,因为我们与外部约定的数据格式一直都比较稳定.但当外部数据不稳定,那么Gson默认 ...

  10. Javascrip随笔1

    isNaN:指示某个值不是数字 文本字符串中使用反斜杠对代码行进行换行; 在计算机程序中,经常会声明无值的变量.未使用值来声明的变量,其值实际上是 undefined.在执行过以下语句后,变量 car ...