• poj 图算法


       ”一蹦三跳“的总算是把图算法写完了,关于割边和割点的没有看,一些题目死活不过的,也没有继续改,各种模糊,各种纠结呀。(中间加杂着考试,课设,还有放假,总之写的很乱,题意的解释,思路的解释,有的直接没解释了,都很乱,代码也没有解释,有的代码也没有贴)

    1. 是差分约束系统,笼统的说就是求解关于一组变量的特殊不等式组的方法。如果你给系统是由n个变量m个约束条件组成,且每个约束条件都形如不等式,那么我们可以从这m个约束条件里发现类似最短路中的三角不等式d[v] <=d[u]+w[u,v],所以差分约束系统就可以转换为单源最短路去求解,主要是看懂题意,建图,然后就是最短路了(注意最短路权值有可能为负)

    题目链接 http://poj.org/problem?id=2983

    题意:给你一些关系,问你是否叙述合理。把等号转换为不等号,注意负环判断

    View Code
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <math.h>
     6 #include <queue>
     7 #define N 200010
     8 #define inf 9999999
     9 
    10 using namespace std;
    11 
    12 struct node
    13 {
    14     int x;
    15     int y;
    16     int wei;
    17 }e[N];
    18 int n,cnt;
    19 int dis[1010];
    20 bool blem()
    21 {
    22     int i,j;
    23     for(i = 1; i <= n; i++)
    24     {
    25         dis[i] = inf;
    26     }
    27     dis[1] = 0;
    28     for(i = 0; i < n - 1; i++)
    29     {
    30         int flag = 0;
    31         for(j = 0; j < cnt; j++)
    32         {
    33             if(dis[e[j].y] > dis[e[j].x] + e[j].wei)
    34             {
    35                 dis[e[j].y] = dis[e[j].x] + e[j].wei;
    36                 flag = 1;
    37             }
    38         }
    39         if(!flag) return true;
    40     }
    41     for(j = 0; j < cnt; j++)
    42     {
    43         if(dis[e[j].y] > dis[e[j].x] + e[j].wei)
    44         {
    45             dis[e[j].y] = dis[e[j].x] + e[j].wei;
    46             return false;
    47         }
    48     }
    49     return true;
    50 }
    51 int main()
    52 {
    53     int i;
    54     int a,b,d;
    55     int m;
    56     char ch;
    57     //freopen("data.txt","r",stdin);
    58     while(cin>>n>>m)
    59     {
    60         getchar();
    61         cnt = 0;
    62         for(i = 0; i < m; i++)
    63         {
    64             scanf("%c",&ch);
    65             if(ch == 'P')
    66             {
    67                 scanf("%d%d%d",&a,&b,&d);
    68                 e[cnt].x = a;
    69                 e[cnt].y = b;
    70                 e[cnt].wei = -d;
    71                 cnt++;
    72                 e[cnt].x = b;
    73                 e[cnt].y = a;
    74                 e[cnt].wei = d;
    75                 cnt++;
    76             }
    77             else
    78             {
    79                 scanf("%d%d",&a,&b);
    80                 e[cnt].x = a;
    81                 e[cnt].y = b;
    82                 e[cnt].wei = -1;
    83                 cnt++;
    84             }
    85             getchar();
    86         }
    87         if(blem()) cout<<"Reliable\n";
    88         else cout<<"Unreliable\n";
    89     }
    90     return 0;
    91 }

     题目http://poj.org/problem?id=1364

    题意:给定长度为N的序列,并给M个关系,要求从第a个序列开始,向后数b个,这些序列之和会<或>某个值,若满足这M个关系,输出"lamentable kingdom",否则输出"successful conspiracy"。

    把> < 改为 >=   <=,然后建立不等式关系 x1 - x2 <= n,然后建边dis(x2,x1)=n。然后用最短路求解

    View Code
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <iostream>
     4 #include <string>
     5 #include <queue>
     6 #include <algorithm>
     7 #define _clr(a,b) (memset(a,b,sizeof(a)))
     8 #define N 110
     9 
    10 using namespace std;
    11 
    12 struct node
    13 {
    14     int s,e;
    15     int next;
    16     int wei;
    17 }map[N * 2];
    18 int dis[N * 2];
    19 int point[N * 2];
    20 int v[N * 2];
    21 int ans[N * 2];
    22 int n,m;
    23 int cnt;
    24 void init()
    25 {
    26     _clr(map,0);
    27     _clr(point,0xff);
    28     cnt = 1;
    29 }
    30 void add(int s,int e,int d)
    31 {
    32     map[cnt].s = s;
    33     map[cnt].e = e;
    34     map[cnt].wei = d;
    35     map[cnt].next = point[s];
    36     point[s] = cnt++;
    37 }
    38 int blem()
    39 {
    40     int i;
    41     _clr(dis,0xff);
    42     dis[0] = 0;
    43     _clr(v,0);
    44     _clr(ans,0);
    45     queue<int>qu;
    46     for(i = 0; i <= n; i++)
    47     qu.push(i);
    48     //qu.push(0);
    49     v[0] = 1;
    50     while(!qu.empty())
    51     {
    52         int temp = qu.front();
    53         qu.pop();
    54         v[temp] = 0;
    55         for(i = point[temp]; i != -1; i = map[i].next)
    56         {
    57             if(dis[map[i].e] > dis[temp] + map[i].wei)
    58             {
    59                 dis[map[i].e] = dis[temp] + map[i].wei;
    60                 if(!v[map[i].e])
    61                 {
    62                     v[map[i].e] = 1;
    63                     qu.push(map[i].e);
    64                     ans[map[i].e] ++;
    65                     if(ans[map[i].e] > n) return 0;
    66                 }
    67             }
    68         }
    69     }
    70     return 1;
    71 }
    72 int main()
    73 {
    74     int i;
    75     int a,b,d;
    76     string ch;
    77     //freopen("data.txt","r",stdin);
    78     while(cin>>n>>m)
    79     {
    80         init();
    81         for(i = 0; i < m; i++)
    82         {
    83             cin>>a>>b>>ch>>d;
    84             if(ch == "gt")
    85             {
    86                 add(a + b,a - 1, -d - 1);
    87             }
    88             else if(ch == "lt")
    89             {
    90                 add(a - 1,a + b,d - 1);
    91             }
    92         }
    93         if(!blem()) printf("successful conspiracy\n");
    94         else printf("lamentable kingdom\n");
    95     }
    96     return 0;
    97 }

    题目:http://poj.org/problem?id=3159

    题意: n个小朋友分糖,A 同学不能容忍 B 同学的糖比他多k+1(最多能多k) ,要你求n号同学最多能多1号同学多少颗糖。

    分析:也就是 ai+k<=aj   =>   aj - ai <=k,差分约束系统 满足条件的a序列转成最短路径dis[j] -dis[i] <=w(i,j)最后求dis[n]-dis[1]即可,这天n 和 m 都挺大,最好用spfa来求解最短路(代码不贴了)

    2. 最小费用最大流,http://www.cppblog.com/Icyflame/archive/2009/06/30/88891.html 一个简单的讲解,但是给出了核心代码。

    题目:http://poj.org/problem?id=2516

    题意:给出N个商店,M个仓库,K种货物,商店的需求,仓库的存货量,以及运输过程中各种货物的运费,求商店的需求能否得到满足,若满足,花费最小的运费是多少。

    View Code
      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <iostream>
      4 #include <queue>
      5 #include <algorithm>
      6 #define N 110
      7 #define inf 99999999
      8 #define _clr(a,val) (memset(a,val,sizeof(a)))
      9 
     10 using namespace std;
     11 
     12 int map[N][N], flow[N][N], cost[N][N];
     13 int pre[N], min_flow[N], dis[N];
     14 int spfa(int num,int s,int e)
     15 {
     16     queue<int>qu;
     17     int i;
     18     for(i = 0; i < num; i++)
     19     {
     20         dis[i] = inf;
     21     }
     22     _clr(pre,-1);
     23     qu.push(s);
     24     dis[s] = 0;
     25     min_flow[s] = inf;
     26     while(!qu.empty())
     27     {
     28         int tem = qu.front();
     29         qu.pop();
     30         for(i = 0; i < num; i++)
     31         {
     32             if((map[tem][i] - flow[tem][i] > 0) && (dis[tem] + cost[tem][i] < dis[i]))
     33             {
     34                 dis[i] = dis[tem] + cost[tem][i];
     35                 pre[i] = tem;
     36                 qu.push(i);
     37                 min_flow[i] = min(min_flow[tem],(map[tem][i] - flow[tem][i]));
     38             }
     39         }
     40     }
     41     if(pre[e] != -1) return 1;
     42     return 0;
     43 }
     44 
     45 int mcmf(int num,int s,int e)
     46 {
     47     int t, ans = 0;
     48     _clr(flow,0);
     49     while(spfa(num,s,e))
     50     {
     51         t = e;
     52         while(pre[t] >= 0)
     53         {
     54             flow[pre[t]][t] += min_flow[e];
     55             flow[t][pre[t]] = -flow[pre[t]][t];
     56             t = pre[t];
     57         }
     58         ans += dis[e] * min_flow[e];
     59     }
     60     return ans;
     61 }
     62 
     63 int main()
     64 {
     65     int n,m,kind,ans;
     66     bool no_ans;
     67     int order[N][N],storage[N][N];
     68     int i,j,k;
     69     //freopen("data.txt","r",stdin);
     70     while(scanf("%d%d%d",&n,&m,&kind))
     71     {
     72         if(!n && !m && !kind) break;
     73         no_ans = 0;
     74         ans = 0;
     75         for(i = 0; i < n; i++)
     76         for(j = 0; j < kind; j++)
     77         scanf("%d",&order[i][j]);
     78         for(i = 0; i < m; i++)
     79         for(j = 0; j < kind; j++)
     80         scanf("%d",&storage[i][j]);
     81         for(i = 0; i < kind; i++)
     82         {
     83             int sum1 = 0;
     84             int sum2 = 0;
     85             for(j = 0; j < n; j++)
     86             sum1 += order[j][i];
     87             for(j = 0; j < m; j++)
     88             sum2 += storage[j][i];
     89             if(sum1 > sum2)
     90             {
     91                 no_ans = 1;
     92                 ans = -1;
     93                 break;
     94             }
     95         }
     96         for(i = 0; i < kind; i++)
     97         {
     98             _clr(cost,0);
     99             for(j = 0; j < n; j++)
    100             {
    101                 for(k = 0; k < m; k++)
    102                 {
    103                     scanf("%d",&cost[n + k][j]);
    104                     cost[j][n + k] = -cost[n + k][j];
    105                 }
    106             }
    107             if(no_ans) continue;
    108             else
    109             {
    110                 _clr(map,0);
    111                 for(j = 0; j < n; j++)
    112                 map[j][n + m] = order[j][i];
    113                 for(j = 0; j < m; j++)
    114                 map[n + m + 1][j + n] = storage[j][i];
    115                 for(j = n; j < n + m; j++)
    116                 {
    117                     for(k = 0; k < n; k++)
    118                     map[j][k] = 10;
    119                 }
    120                 ans += mcmf(n + m + 2, n + m + 1, m + n);
    121             }
    122         }
    123         printf("%d\n",ans);
    124     }
    125     return 0;
    126 }

    题目:http://poj.org/problem?id=2195

    题意:有n个小孩和n个房间,问每个小孩都有一个房间的最小花费

    View Code
      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <iostream>
      4 #include <queue>
      5 #include <stdlib.h>
      6 #define N 210
      7 #define inf 1000000001
      8 #define _clr(a,val) (memset(a,val,sizeof(a)))
      9 
     10 using namespace std;
     11 
     12 struct node
     13 {
     14     int x,y;
     15 }man[N],house[N];
     16 char str[N][N];
     17 int map[N][N];
     18 int cost[N][N];
     19 int n,m;
     20 int nman,nhouse;
     21 int ans;
     22 void mcmf(int s,int e,int n)
     23 {
     24     int i;
     25     queue<int>qu;
     26     int d[N],flow[N][N],pre[N];
     27     _clr(flow,0);
     28     int c,f;
     29     f = c = 0;
     30     for(;;)
     31     {
     32         int inq[N];
     33         for(i = 0; i < n; i++)
     34         d[i] = inf;
     35         d[s] = 0;
     36         while(!qu.empty()) qu.pop();
     37         _clr(inq,0);
     38         inq[s] = 1;
     39         qu.push(s);
     40         while(!qu.empty())
     41         {
     42             int u = qu.front();
     43             qu.pop();
     44             inq[u] = 0;
     45             for(i = 0; i < n; i++)
     46             if(map[u][i] > flow[u][i] && d[i] > d[u] + cost[u][i])
     47             {
     48                 d[i] = d[u] + cost[u][i];
     49                 pre[i] = u;
     50                 if(!inq[i])
     51                 {
     52                     inq[i] = 1;qu.push(i);
     53                 }
     54             }
     55         }
     56         if(d[e] == inf) 
     57         {
     58             break;
     59         }
     60         int a = inf;
     61         for(i = e; i != s; i = pre[i])
     62         {
     63             if(a > map[pre[i]][i] - flow[pre[i]][i])
     64             a = map[pre[i]][i] - flow[pre[i]][i];
     65         }
     66         for(i = e; i != s; i = pre[i])
     67         {
     68             flow[pre[i]][i] += a;
     69             flow[i][pre[i]] -= a;
     70         }
     71         ans += d[e] * a;
     72         f += a;
     73     }
     74 }
     75 int main()
     76 {
     77     int i,j;
     78     //freopen("data.txt","r",stdin);
     79     while(scanf("%d%d",&n,&m),m + n)
     80     {
     81         getchar();
     82         nman = nhouse = 0;
     83         for(i = 0; i < n; i++)
     84         {
     85             for(j = 0; j < m; j++)
     86             {
     87                 cin>>str[i][j];
     88                 if(str[i][j] == 'm')
     89                 {
     90                     man[nman].x = i;
     91                     man[nman].y = j;
     92                     nman++;
     93                 }
     94                 else if(str[i][j] == 'H')
     95                 {
     96                     house[nhouse].x = i;
     97                     house[nhouse].y = j;
     98                     nhouse++;
     99                 }
    100             }
    101         }
    102         int num = nman + nhouse;
    103         _clr(map,0);
    104         for(i = 0; i < num + 2; i++)
    105         {
    106             for(j = 0; j < num + 2; j++)
    107             cost[i][j] = inf;
    108         }
    109         for(i = 0; i < nman; i++)
    110         {
    111             for(j = 0; j < nhouse; j++)
    112             {
    113                 map[i + 1][j + nman + 1] = 1;
    114                 cost[i + 1][j + nman + 1] = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y);
    115                 cost[j + nman + 1][i + 1] = -cost[i + 1][j + nman + 1];
    116             }
    117         }
    118         for(i = 1; i <= nman; i++)
    119         {
    120             map[0][i] = 1;
    121             cost[0][i] = 0;
    122         }
    123         for(i = nman + 1; i <= num; i++)
    124         {
    125             map[i][num + 1] = 1;
    126             cost[i][num + 1] = 0;
    127         }
    128         ans = 0;
    129         mcmf(0,num + 1,num + 2);
    130         cout<<ans<<endl;
    131     }
    132     return 0;
    133 }

    3. 强连通分量,强连通分量的定义参见维基百科  http://zh.wikipedia.org/wiki/%E5%BC%BA%E8%BF%9E%E9%80%9A%E5%88%86%E9%87%8F 虽然说是有三种方法求解,但看网上的介绍主要是用tarjin算法来写的,感觉这个人写的很详细http://www.byvoid.com/blog/scc-tarjan/对照着他的代码,和画的图,理解算法应该是不难的。

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1269

    最裸的模板套用,以前看题还以为是根据dfs搜路径,然后再倒着搜一遍。原来是强连通分量题目,题意就不说了。

    判断所给的点是不是在一个强连通分量里,如果是则输出“YES”,否则’NO“

    View Code
     1 #include <iostream>
     2 #include <string.h>
     3 #include <algorithm>
     4 #include <stack>
     5 #include <queue>
     6 #include <math.h>
     7 #include <stdlib.h>
     8 #include <stdio.h>
     9 #define N 10010
    10 #define M 50010
    11 #define _clr(a,val) (memset(a,val,sizeof(a)))
    12 
    13 using namespace std;
    14 
    15 struct node
    16 {
    17     int from;
    18     int to;
    19     int next;
    20 }eage[M * 2];
    21 stack<int>st;
    22 int n,m;
    23 int dfn[N],low[N];
    24 int v[N],head[N];
    25 int bh[N],val[N];
    26 int out[N];
    27 int num,cou,ind;
    28 void add(int f,int t)
    29 {
    30     eage[num].from = f;
    31     eage[num].to = t;
    32     eage[num].next = head[f];
    33     head[f] = num++;
    34 }
    35 void tarjin(int u)
    36 {
    37     int j,t,s;
    38     dfn[u] = low[u] = ind++;
    39     v[u] = 1;
    40     st.push(u);
    41     for(j = head[u]; j != -1; j = eage[j].next)
    42     {
    43         t = eage[j].to;
    44         if(!v[t])
    45         {
    46             tarjin(t);
    47             low[u] = min(low[u],low[t]);
    48         }
    49         else low[u] = min(low[u],dfn[t]);
    50     }
    51     //cout<<"{";
    52     if(dfn[u] == low[u])
    53     {
    54         cou++;
    55         do
    56         {
    57             s = st.top();
    58             st.pop();
    59             //cout<<s<<",";
    60             bh[s] = cou;
    61         }while(s != u);
    62         //cout<<"}";
    63     }
    64 }
    65 int main()
    66 {
    67     int i;
    68     int x,y;
    69     //freopen("data.txt","r",stdin);
    70     while(scanf("%d%d",&n,&m) != EOF)
    71     {
    72         if(!n && !m) break;
    73         _clr(head,-1);
    74         _clr(v,0);
    75         _clr(dfn,0);
    76         _clr(low,0);
    77         _clr(bh,0);
    78         num = ind = cou = 0;
    79         while(m--)
    80         {
    81             scanf("%d%d",&x,&y);
    82             add(x,y);
    83         }
    84 
    85         for(i = 1; i <= n; i++)
    86         if(!v[i]) tarjin(i);
    87         //cout<<"*****\n";
    88         int tem = bh[1];
    89         int flag = 0;
    90         for(i = 1; i <= n; i++)
    91         {
    92             if(tem != bh[i]) {flag = 1; break;}
    93         }
    94         if(!flag) cout<<"Yes\n";
    95         else cout<<"No\n";
    96     }
    97     return 0;
    98 }

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3836

    简单的题意就是:给出一个连通图,问加几条边可以让这个连通图变为强量同分量 。max(入度为零的个数,出度为零的个数),如果原图是一个强连通的,那么输出0

    View Code
     1 #include<iostream>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<stdio.h>
     5 #include<string>
     6 #define N 20005
     7 #define M 500005
     8 using namespace std;
     9 bool istack[N];
    10 int dfn[N],low[N],in[N],out[N],belong[N],stack[N],head[N];
    11 typedef struct str
    12 {
    13     int to;
    14     int next;
    15 }Node;
    16 Node node[M];
    17 int res,num,top,ind,n,m;
    18 void init()
    19 {
    20     memset(istack,false,sizeof(istack));
    21     memset(head,-1,sizeof(head));
    22     memset(dfn,0,sizeof(dfn));
    23     memset(low,0,sizeof(low));
    24     memset(in,0,sizeof(in));
    25     memset(out,0,sizeof(out));
    26     memset(stack,0,sizeof(stack));
    27     memset(belong,0,sizeof(belong));
    28     res=num=top=0;
    29     ind=1;
    30 }
    31 void dfs(int i)
    32 {
    33     dfn[i]=low[i]=ind++;
    34     istack[i]=true;
    35     stack[top++]=i;
    36     for(int j=head[i];j!=-1;j=node[j].next)
    37     {
    38         int v=node[j].to;
    39         if(!dfn[v])
    40         {
    41             dfs(v);
    42             low[i]=min(low[i],low[v]);
    43         }
    44         else if(istack[v])
    45             low[i]=min(low[i],dfn[v]);
    46     }
    47     int u;
    48     if(dfn[i]==low[i])
    49     {
    50         res++;
    51         do
    52         {
    53              u=stack[--top];
    54              istack[u]=false;
    55              belong[u]=res;
    56         }while(u!=i);
    57      }
    58 }
    59 void tarjan()
    60 {
    61     for(int i=1;i<=n;++i)
    62         if(!dfn[i]) dfs(i);
    63 }
    64 void solve()
    65 {   if(res==1) {cout<<"0"<<endl;return;}
    66     for(int i=1;i<=n;++i)
    67         for(int j=head[i];j!=-1;j=node[j].next)
    68            if(belong[i]!=belong[node[j].to])
    69            {
    70                out[belong[i]]++;
    71                in[belong[node[j].to]]++;
    72            }
    73            int p=0,q=0;
    74            for(int i=1;i<=res;++i)
    75            {
    76                if(!out[i]) p++;
    77                if(!in[i]) q++;
    78            }
    79            cout<<max(p,q)<<endl;
    80 }
    81 int main()
    82 {
    83     //freopen("data.txt","r",stdin);
    84     while(cin>>n>>m)
    85     {
    86       init();
    87       for(int i=0;i!=m;++i)
    88       {
    89           int a,b;
    90            cin>>a>>b;
    91            node[num].to = b;
    92            node[num].next = head[a];
    93            head[a] = num++;
    94       }
    95       tarjan();
    96       solve();
    97     }return 0;
    98 }

    题目:http://poj.org/problem?id=1236

    题意:N个高校之间有一些单向的网络链接(N<100),当发布一个软件时,学校i收到软件时,它可以将软件发送给所有它链接到的学校。现在要求发布一款软件,最少需要发给多少个学校,使得所有学校都可以收到软件(问题A)。最少需要添加多少条单向网络链接,可以使得将软件任意发给一个学校,使得所有学校都可以收到(问题B)。

    问题A被称为求最小基点问题,首先,求出有向图的极大强连通分量,在同一个强连通分量里的学校任意一个收到软件,整个强连通分量里的学校都可以收到。将每个强连通分量缩成一个点,构成一个新的有向无环图。当强连通分量i收到软件,那么i可达的强连通分量都可以收到软件。

    我们称入度为0的强连通分量为最高强连同分量。显然,每个最高强连通分量都必须单独发送一次软件,而其他强连通分量都可以通过最高强连通分量到达。所以,最高强连通分量的个数也就是问题A的答案

    问题B,是max(入度为零的个数,出度为零的个数)注意的是,当原图只有一个强连通分量是,问题B的答案是0。

    View Code
      1 #include <iostream>
      2 #include <string.h>
      3 #include <algorithm>
      4 #include <stack>
      5 #include <queue>
      6 #include <math.h>
      7 #include <stdlib.h>
      8 #include <stdio.h>
      9 #define N 101
     10 #define M 10010
     11 #define inf 100000000
     12 #define _clr(a,val) (memset(a,val,sizeof(a)))
     13 
     14 using namespace std;
     15 
     16 struct node
     17 {
     18     int from;
     19     int to;
     20     int next;
     21 }eage[M * 2];
     22 int dfn[N],low[N];
     23 int head[N],v[N];
     24 int in[N],out[N];
     25 int map[N][N];
     26 int bh[N];
     27 int ind,num,cou;
     28 stack<int>st;
     29 int n,m;
     30 void add(int f,int t)
     31 {
     32     eage[num].from = f;
     33     eage[num].to = t;
     34     eage[num].next = head[f];
     35     head[f] = num++;
     36 }
     37 void tarjin(int i)
     38 {
     39     int j,s,t;
     40     dfn[i] = low[i] = ++ind;
     41     v[i] = 1;
     42     st.push(i);
     43     for(j = head[i]; j != -1; j = eage[j].next)
     44     {
     45         t = eage[j].to;
     46         if(!dfn[t])
     47         {
     48             tarjin(t);
     49             low[i] = min(low[i],low[t]);
     50         }
     51         else if(v[t]) low[i] = min(dfn[t],low[i]);
     52     }
     53     if(dfn[i] == low[i])
     54     {
     55         cou++;
     56         do
     57         {
     58             s = st.top();
     59             st.pop();
     60             bh[s] = cou;
     61             v[s] = 0;
     62         }while(i != s);
     63     }
     64 }
     65 void ca()
     66 {
     67     int i,j;
     68     for(i = 1; i <= n; i++)
     69     if(!dfn[i]) tarjin(i);
     70     _clr(out,0);
     71     _clr(in,0);
     72     for(i = 1; i <= n; i++)
     73     {
     74         for(j = head[i]; j != -1; j = eage[j].next)
     75         {
     76             int x = bh[i];
     77             int y = bh[eage[j].to];
     78             if(x != y)
     79             {
     80                 out[x]++;
     81                 in[y]++;
     82             }
     83         }
     84     }
     85     int sum = 0;
     86     int ttsum = 0;
     87     for(i = 1;i <= cou; i++)
     88     {
     89         if(!in[i]) sum++;
     90     }
     91     if(cou == 1)
     92     {
     93         cout<<sum<<"\n0\n";
     94         return ;
     95     }
     96     else
     97     for(i = 1;i <= cou; i++)
     98     {
     99         if(!out[i]) ttsum++;
    100     }
    101     cout<<sum<<"\n"<<max(sum,ttsum)<<endl;
    102 }
    103 int main()
    104 {
    105     int i;
    106     int x;
    107     //freopen("data.txt","r",stdin);
    108     while(cin>>n)
    109     {
    110         _clr(head,-1);
    111         _clr(dfn,0);
    112         _clr(v,0);
    113         _clr(low,0);
    114         _clr(bh,0);
    115         ind = 0;
    116         cou = num = 0;
    117         for(i = 1; i <= n; i++)
    118         {
    119             while(cin>>x,x)
    120             {
    121                 add(i,x);
    122             }
    123         }
    124         ca();
    125     }
    126     return 0;
    127 }

    题目:http://poj.org/problem?id=2942

    题目大意:骑士在圆桌上开会人数是奇数(大于1) 互相憎恨的骑士不能做在一起,问有多少个骑士永远不能坐在圆桌上,注意可以不同时坐在一起 可以分批

    首先是求出图中含有的块,然后找奇圈,一个连通分量里面只要有奇圈,那么这个分量里面的所有的点都可以在某个奇圈里面,判断是否为奇圈的方法是看这个图是否为二分图,如果是二分图,则一定没有奇圈,判断二分图的方法是用染色法,dfs黑白染色,将一顶点a染成黑色,和a相邻的点染成白色。这样如果一条边上的两个点的颜色相同,说明该图不是二分图。

    View Code
      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <iostream>
      4 #include <stack>
      5 #define N 1010
      6 #define M 1000010
      7 #define _clr(a,val) (memset(a,val,sizeof(a)))
      8 
      9 using namespace std;
     10 
     11 struct node
     12 {
     13     int from;
     14     int to;
     15     int next;
     16 }eage[M * 2];
     17 stack<int>st;
     18 int n,m;
     19 int num,cnt;
     20 int flag,cou;
     21 int color[N],bh[N];
     22 int v[N],vis[N];
     23 int map[N][N];
     24 int head[N];
     25 int dfn[N],low[N];
     26 int val[N];
     27 void add(int f,int t)
     28 {
     29     eage[num].from = f, eage[num].to = t;
     30     eage[num].next = head[f], head[f] = num++;
     31     eage[num].from = t, eage[num].to = f;
     32     eage[num].next = head[t], head[t] = num++;
     33 }
     34 void dfs(int ind,int col)
     35 {
     36     int i,t;
     37     color[ind] = col;
     38     for(i = head[ind]; i != -1; i = eage[i].next)
     39     {
     40         t = eage[i].to;
     41         if(bh[t] != cou) continue;
     42         if(color[t] == 1 - col) continue;
     43         if(color[t] == -1) dfs(t,1 - col);
     44         else if(color[t] == col) flag = 1;
     45         if(flag) return ;
     46     }
     47 }
     48 void tarjin(int u,int f)
     49 {
     50     int i,t,s,j,ans;
     51     dfn[u] = low[u] = cnt++;
     52     vis[u] = 1;
     53     st.push(u);
     54     for(i = head[u]; i != -1; i = eage[i].next)
     55     {
     56         t = eage[i].to;
     57         if(t == f) continue;
     58         if(!vis[t])
     59         {
     60             tarjin(t,u);
     61             low[u] = min(low[u],low[t]);
     62             if(low[t] >= dfn[u])
     63             {
     64                 cou++;
     65                 ans = 0;
     66                 do
     67                 {
     68                     s = st.top();
     69                     st.pop();
     70                     val[++ans] = s;
     71                     bh[s] = cou;
     72                 }while(s != t);
     73             bh[u] = cou;
     74             val[++ans] = u;
     75             flag = 0;
     76             _clr(color,-1);
     77             dfs(u,0);
     78             if(flag)
     79             {
     80                 for(j = 1; j <= ans; j++)
     81                 v[val[j]] = 1;
     82             }
     83             }
     84         }
     85         else low[u] = min(low[u],dfn[t]);
     86     }
     87 }
     88 int main()
     89 {
     90     int i,j;
     91     int x,y;
     92     //freopen("data.txt","r",stdin);
     93     while(scanf("%d%d",&n,&m), n + m)
     94     {
     95         _clr(map,0);
     96         while(m--)
     97         {
     98             scanf("%d%d",&x,&y);
     99             map[x][y] = map[y][x] = 1;
    100         }
    101         num = cnt = cou = 0;
    102         _clr(head,-1);
    103         for(i = 1; i <= n; i++)
    104         {
    105             for(j = i + 1; j <= n; j++)
    106             if(map[i][j] == 0)
    107             {
    108                 add(i,j);
    109             }
    110         }
    111         int sum = 0;
    112         _clr(bh,-1);
    113         _clr(v,0);
    114         _clr(vis,0);
    115         _clr(dfn,0);
    116         _clr(low,0);
    117         for(i = 1; i <= n; i++)
    118         if(!vis[i]) tarjin(i,-1);
    119         for(i = 1; i <= n; i++)
    120         if(v[i]) sum++;
    121         printf("%d\n",n - sum);
    122     }
    123     return 0;
    124 }

    4. KM算法   如果还没有看匈牙利二分匹配的,最好先去看一小那个,km是建立在二分匹配的基础上做的,一个讲解链接 http://www.cppblog.com/MatoNo1/archive/2011/07/23/151724.aspx 

    题目:http://poj.org/problem?id=2400

    题意: n个雇主n个员工, 每个雇主对每个员工有不同的喜好值0~n-1, 0表示最喜欢, 每个员工对每个雇主也有喜好值, 定义同前, 问怎样分配使得总喜好值对2n个人取平均的值最小, 按字典序输出所有方案. 

    把雇主对员工的喜爱值和员工对雇主的喜爱值建立矩阵,然后用km算法模板,km一次,再用dfs搜索路径

    View Code
      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <iostream>
      4 #include <algorithm>
      5 #define N 20
      6 #define inf 10000000
      7 #define _clr(a,val) (memset(a,val,sizeof(a)))
      8 
      9 using namespace std;
     10 
     11 int map[N][N],v[N];
     12 int lx[N],ly[N];
     13 int vx[N],vy[N];
     14 int match[N],path[N];
     15 int n,cnt;
     16 int dfs(int x)
     17 {
     18     int i;
     19     vx[x] = 1;
     20     for(i = 1; i <= n; i++)
     21     {
     22         if(!vy[i] && lx[x] + ly[i] == map[x][i])
     23         {
     24             vy[i] = 1;
     25             if(match[i] == -1 || dfs(match[i]))
     26             {
     27                 match[i] = x;
     28                 return 1;
     29             }
     30         }
     31     }
     32     return 0;
     33 }
     34 int km()
     35 {
     36     int i,j,k;
     37     _clr(match,-1);
     38     for(i = 1; i <= n; i++)
     39     {
     40         lx[i] = inf;
     41         for(j = 1; j <= n; j++)
     42         if(lx[i] < map[i][j]) lx[i] = map[i][j];
     43     }
     44     _clr(ly,0);
     45     for(i = 1; i <= n; i++)
     46     {
     47         while(1)
     48         {
     49             _clr(vx,0);
     50             _clr(vy,0);
     51             if(dfs(i)) break;
     52             int minn = inf;
     53             for(j = 1; j <= n; j++)
     54             {
     55                 if(vx[j])
     56                 {
     57                     for(k = 1; k <= n; k++)
     58                     if(!vy[k] && lx[j] + ly[k] - map[j][k] < minn)
     59                     {
     60                         minn = lx[j] + ly[k] - map[j][k];
     61                     }
     62                 }
     63             }
     64             for(j = 1; j <= n; j++)
     65             {
     66                 if(vx[j]) lx[j] -= minn;
     67                 if(vy[j]) ly[j] += minn;
     68             }
     69         }
     70     }
     71     int sum = 0;
     72     for(i = 1; i <= n; i++)
     73     sum -= map[match[i]][i];
     74     return sum;
     75 }
     76 void out(int sum)
     77 {
     78     int i;
     79     if(sum  > n)
     80     {
     81         printf("Best Pairing %d\n",++cnt);
     82         for(i = 1; i <= n; i++)
     83         {
     84             //if(i == n) printf("Supervisor %d with Employee %d\n",i,path[0]);
     85             //else printf("Supervisor %d with Employee %d\n",i,path[i]);
     86             printf("Supervisor %d with Employee %d\n",i,path[i]);
     87         }
     88     }
     89     else
     90     {
     91         for(i = 1; i <= n; i++)
     92         if(lx[sum] + ly[i] == map[sum][i] && !v[i])
     93         {
     94             v[i] = 1;
     95             path[sum] = i;
     96             out(sum + 1);
     97             v[i] = 0;
     98         }
     99     }
    100 }
    101 int main()
    102 {
    103     int t,cs = 0;
    104     int i,j;
    105     int temp;
    106     //freopen("data.txt","r",stdin);
    107     scanf("%d",&t);
    108     while(t--)
    109     {
    110         _clr(map,0);
    111         scanf("%d",&n);
    112         for(i = 1; i <= n; i++)
    113         {
    114             for(j = 0; j < n; j++)
    115             {
    116                 scanf("%d",&temp);
    117                 map[temp][i] -= j;
    118             }
    119         }
    120         for(i = 1; i <= n; i++)
    121         {
    122             for(j = 0; j < n; j++)
    123             {
    124                 scanf("%d",&temp);
    125                 map[i][temp] -= j;
    126             }
    127         }
    128         int ans = km();
    129         printf("Data Set %d, Best average difference: %.6lf\n",++cs,(ans * 1.0) / (2 * n));
    130         cnt = 0;
    131         _clr(path,0);
    132         _clr(v,0);
    133         out(1);
    134         printf("\n");
    135     }
    136     return 0;
    137 }

    题目:

    题意: 有N个工件要在M个机器上加工,有一个N*M的矩阵描述其加工时间。 同一时间内每个机器只能加工一个工件,问加工完所有工件后,使得平均加工时间最小。注意工件是有等待时间的,当一个机器在加工一个工件时,其他的都在等待即   若某台机器按顺序执行k个任务,且k个任务的执行时间分别为t1,t2…tk,则k个任务的总的执行时间是
    t1*k+t2*(k-1)+t3*(k-2)+…+tk-1*2+tk

    建图时   分两个集合  X集有N个点(N个工件),Y集是由拆分成的 N*M个点 组成。即每一个工件I都可能机器J的倒数第K1~N)个顺序完成,则这样建图:w[i][j-1*N+k]  =   -k*tmp[i][j]。然后用KM求最大权

  • 相关阅读:
    HTTP网页错误代码大全带解释
    记录一下手把手教您做电商网站
    C#中的Attribute
    C#中dynamic的正确用法
    【CSP】最大的矩形
    【CSP】字符与int
    C++数组初始化
    C++中输出字符到文本文档
    C++ 中时钟函数的使用
    各种函数的头文件
  • 原文地址:https://www.cnblogs.com/fxh19911107/p/2605861.html
Copyright © 2020-2023  润新知