您的位置:首页 > 其它

防2B && 图论模板 && 7788

2013-10-11 22:16 190 查看
1.二分图判定染色模板

bool dfs(int u, int cur){
col[u]=cur;
for(int i=0; i<g[u].size(); i++){
int v=g[u][i];
if(col[u]==col[v] || (!col[v] && !dfs(v, 3-cur))) return false;
}
return true;
}


2.floyd模板

void floyd(){                           //求可达性
int k, i, j;
for(k=1; k<=n; k++)
for(i=1; i<=n; i++)
for(j=1; j<=n; j++) if(!reach[i][j])
reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
}


3.tarjan 求 割边 / 桥

void dfs(int u){
dfn[u]=low[u]=++tsp;
vis[u]=ins[u]=true;         s.push(u);
for(int i=h[u]; i!=-1; i=e[i].nxt){
int v=e[i].v;
if(!vis[v]){
ve[e[i].re]=true;
dfs(v), low[u]=MIN(low[v], low[u]);
if(dfn[v]==low[v]) ans=MIN(ans, e[i].w);    //割点,割边
}
else if(ins[v] && !ve[i]){
ve[e[i].re]=true;
low[u]=MIN(dfn[v], low[u]);
}
}
if(dfn[u]==low[u]){             //割点
int v;
do{
v=s.top();      s.pop();
ins[v]=false;
}while(v!=u);
}
}

void tarjan(){
int i, j;
memset(vis, 0, sizeof(vis));
memset(ve, 0, sizeof(ve));
memset(ins, 0, sizeof(ins));
int f=tsp=0;
for(i=1; i<=n; i++) if(!vis[i])
dfs(i), f++;
if(f>1) ans=0;
if(ans==INF)  ans=-1;
}


4.tarjan 求强连通分量

void tarjan(int u){
dfn[u]=low[u]=++tsp;
s.push(u);      ins[u]=true;
int i, v, tl=g[u].size();
for(i=0; i<tl; i++){
v=g[u][i];
if(!dfn[v]) tarjan(v), low[u]=MIN(low[u], low[v]);
else if(ins[v]) low[u]=MIN(low[u], dfn[v]);             //ins避免横叉边
}
if(low[u]==dfn[u]){             //将强连通分量缩为一点
cnt++;      num[cnt]=0;
//     cout<<cnt<<endl;
do{
v=s.top();      s.pop();
//       cout<<' '<<v;
id[v]=cnt;
ins[v]=false;
num[cnt]++;
}while(v!=u);
//     cout<<"\tnumber:"<<num[cnt]<<endl;
}
}


5.tarjan 求点双连通分量

void tarjan(int u, int fa){
int v, child=0;
dfn[u]=low[u]=++tsp;
for(unsigned int i=0; i<g[u].size(); i++){
v=g[u][i];
edge t;     t.u=u;      t.v=v;
if(!dfn[v]){
child++;
s.push(t);
tarjan(v, u);
low[u]=MIN(low[u], low[v]);
if(low[v]>=dfn[u]){
iscut[u]=1;
edge k;
bcc[++cnt].clear();
while(1){
k=s.top();      s.pop();
if(id[k.u] != cnt) {id[k.u]=cnt; bcc[cnt].push_back(k.u);}
if(id[k.v] != cnt) {id[k.v]=cnt; bcc[cnt].push_back(k.v);}
if(k.u==u && k.v==v) break;
}
}
}
else if(dfn[v]<dfn[u] && v!=fa) s.push(t), low[u]=MIN(low[u], dfn[v]);
}
if(fa<0 && child==1) iscut[u]=0;
}


[b]6.tarjan 边双连通分量[/b]

void tarjan(int u){
int i,v;
dfn[u]=low[u]=++tsp;
s[top++]=u;
for(i=h[u]; i!=-1; i=e[i].nxt){
v=e[i].v;
if(!dfn[v]){
vis[e[i].re]=1;
tarjan(v);
low[u]=MIN(low[u], low[v]);
}
else if(!vis[i]) low[u]=MIN(low[u], dfn[v]);        //回边不是反向边,且该点:dfn[v] == low[v]
}
if(low[u] == dfn[u]){
cnt++;
do{
v=s[--top];
id[v]=cnt;              //缩点
}while(v!=u);
}
}


7.稳定婚姻问题 / propose-and-reject algorithm

void engage(int man, int woman){
int m=fb[woman];
if(m) q.push(m), fw[m]=0;           //如果有未婚夫,抛弃
fw[man]=woman;
fb[woman]=man;
}

void solve(){
memset(fw, 0, sizeof(fw));
memset(fb, 0, sizeof(fb));
while(!q.empty()){
int man=q.front();      q.pop();
int woman=pref[man][nxt[man]++];
if(!fb[woman]) engage(man, woman);          //没有未婚夫
else if(order[woman][fb[woman]]>order[woman][man]) engage(man, woman);   //出现更迷人的汉子
else q.push(man);
}
for(int i=1; i<=n; i++) cout<<manname[i]<<' '<<womanname[fw[i]]<<endl;
}


(详细见这里:http://www.cnblogs.com/ramanujan/p/3320659.html)

8.2-sat

inline void add(int u, int a, int v, int b){            //加边
u = (u<<1) + a;
v = (v<<1) + b;
g[u].push_back(v^1);
g[v].push_back(u^1);
}

bool dfs(int u){
if(mark[u]) return true;                        //如果已标记过
if(mark[u^1]) return false;                     //如果否命题假设为真,则矛盾
mark[u]=true;       s[c++]=u;
int i, tl=g[u].size();

for(i=0; i<tl; i++)
if(!dfs(g[u][i])) return false;
return true;
}

void solve(int n, int ave){
int i,j;
memset(mark, 0, sizeof(mark));
for(i=0; i<n<<1; i+=2) if(!mark[i] && !mark[i+1]){
c=0;
if(!dfs(i)){                        //标记i
while(c--) mark[s[c]]=false;
if(!dfs(i+1)){                  //标记否命题
printf("No solution.\n");
return ;
}
}
}
}


9.扩栈指令(用C++交才有效?):

#pragma comment(linker,"/STACK:102400000,102400000")


10.Bellman-Ford Algorithm 队列实现

queue<int> q;
int bford(int s, int n){
int u,i,w,v;
while(!q.empty()) q.pop();  q.push(s);
//   memset(cnt, 0, sizeof(cnt));    cnt[s]=1;
memset(inq, 0, sizeof(inq));    inq[s]=1;
for(i=0; i<n; i++) d[i]=INF;    d[s]=0;
while(!q.empty()){
u=q.front();    q.pop();    inq[u]=0;
for(i=h[u]; i!=-1; i=e[i].nxt){
v=e[i].v;
w=e[i].w;
if(d[v]>d[u]+w){
d[v]=d[u]+w;
if(!inq[v]){
//                if(++cnt[v]>n) return 1;
q.push(v);
inq[v]=1;
}
}
}
}
ans=d[s-1]-d[0];            // 结果不是d[s-1]么?。。。
return 0;
}


11.朱刘算法(抄来:http://www.cnblogs.com/nanke/archive/2012/04/11/2441725.html#commentform)

int mdst(int s, int n, int m){
int u,v,i,d;
int ret=0;
while(true){            //找出每个点的最小入弧
for(i=0; i<n; i++)
inv[i]=INF;
for(i=0; i<m; i++){
u=e[i].u;
v=e[i].v;
d=e[i].d;
if(d<inv[v] && u!=v){
inv[v]=d;   pre[v]=u;
if(u==s) roote=i;        //要求的根
}
}                               //当前点集合中有点不可达,则图不连通
for(i=0; i<n; i++) if(inv[i]==INF && i!=s)
return -1;
inv[s]=0;
int cnt=0;
memset(id, -1, sizeof(id));
memset(visit, -1, sizeof(visit));
for(i=0; i<n; i++){                 //缩圈
ret+=inv[i];
v=i;                            //如果v还没标记且非虚根
while(visit[v]!=i && id[v]==-1 && v!=s){
visit[v]=i;     v=pre[v];
}                               //这里表明上步visit[v]=i,即有圈
if(v!=s && id[v]==-1){
for(u=pre[v]; u!=v; u=pre[u])
id[u]=cnt;
id[v]=cnt++;
}
}
if(!cnt) break;                     //如果没圈
for(i=0; i<n; i++) if(id[i]==-1)
id[i]=cnt++;
for(i=0; i<m; i++){                 //更新缩圈后各边
u=e[i].u;   v=e[i].v;   d=e[i].d;
e[i]=(edge){id[u], id[v], (u==v ? d : d-inv[v])};
}                                   //保证下次迭代选出正确的inv[v]值
n=cnt;
s=id[s];
}
return ret;
}


12.欧拉回路

//判断欧拉回路:
//1.图是否连通    2.是否存在奇点    3.打印欧拉回路
void dfs(int s){
for(int i=1; i<=50; i++) if(g[s][i]){
g[s][i]--;  g[i][s]--;
dfs(i);
ans.push_back((edge){s,i});
}
}


13.次小生成树(mst + dfs + 枚举边)

int p[MAXN];            //并查集
int finds(int x){
if(p[x]==-1) return x;
else return (p[x]=finds(p[x]));
}

bool vis[MAXM];
int w[MAXN][MAXN];
int mst(){              //kruskal
fill_n(p+1, n, -1);
fill_n(vis, m, false);
for(int i=1; i<=n; i++) g[i].clear();
sort(e, e+m);

int ans=0;
for(int i=0, j=0; i<m; i++){
int x = e[i].u, y = e[i].v, d = e[i].d;
int fx = finds(x), fy = finds(y);
if(fx!=fy){
p[fx]=fy;
ans+=d;                 vis[i]=true;
g[x].push_back(y);      w[x][y]=w[y][x]=d;
g[y].push_back(x);              //请用双向边,否则可WAWAWA
if(++j==n-1) break;
}
}
return ans;
}

int maxcst[MAXN][MAXN];
vector<int> pre;

//求mst中任意两点间的最大边权
void dfs(int u, int fa){
for(int i=0; i<pre.size(); i++){
int v = pre[i], d = w[fa][u];
maxcst[u][v]=maxcst[v][u]=
MAX(d, maxcst[fa][v]);
}
pre.push_back(u);
for(int i=0; i<g[u].size(); i++) if(fa!=g[u][i])
dfs(g[u][i], u);
}

//求mst,次小生成树权值
int fir = mst();
for(i=1; i<=n; i++) fill_n(maxcst[i]+1, n, -1);
pre.clear();
dfs(1, -1);
int sec = INF;
for(i=0; i<m; i++) if(!vis[i]){
int u = e[i].u, v = e[i].v, d = e[i].d;
sec=MIN(sec, fir-maxcst[u][v]+d);
}
printf("%d %d\n", fir, sec);        //mst权值,次小生成树权值


14.优先队列优化的 Dijkstra

void Dijkstra(int s){
for(int i=0; i<=mVertex; i++) dis[i]=INF;   dis[s]=0;
priority_queue<node> q;   q.push((node){0,s});
memset(done, 0, sizeof(done));
while(!q.empty()){
node t=q.top();     q.pop();
int u_ = t.u;
if(done[u_]) continue;  done[u_]=true;
for(int x=h[u_]; x!=-1; x=next[x]) if(dis[v[x]]-dis[u_]>w[x]){
dis[v[x]] = dis[u_] + w[x];
p[v[x]] = x;
q.push((node){dis[v[x]],v[x]});
}
}
}


15.2B了再补吧。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: