【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