• [hdu7074]Little prince and the garden of roses


    显然每种颜色的花是独立的,可以分别求出答案后取$max$

    对于某种颜色$C$,建立一张二分图,左右分别为$n$行$n$列,且第$i$行和第$j$列有边当且仅当$c_{i,j}=C$

    此时,问题即对边染色,并要求相同颜色的边没有公共端点,并最少化颜色数(包含初始颜色)

    这是二分图的边着色问题,其答案即二分图中所有点度数的最大值(记为$Delta$)

    显然这些颜色是必要的(即不能更少),下面构造来说明这是足够的——

    做法1:

    依次对边染色(顺序任意),若当前边存在某种剩余的颜色即使用,否则总存在一种颜色$c_{1}$和$c_{2}$,满足两者分别不在以$x$和$y$为端点的边中出现

    (如果不存在,不难得到$x$或$y$的度数大于颜色数)

    另一方面,由于$c_{1}$和$c_{2}$都不能使用,那么$c_{1}$和$c_{2}$必然分别在以$y$和$x$为端点的边中出现

    不妨假设$c_{1}$在边$(y,z_{0})$上使用,并分类讨论:

    1.$c_{2}$不在以$z_{0}$为端点的边中出现,那么将$(x,y)$和$(y,z_{0})$分别染成$c_{1}$和$c_{2}$即可

    2.$c_{2}$在以$z_{0}$为端点的边中出现,假设为$(z_{0},z_{1})$,考虑重新染$(z_{0},z_{1})$,再分类讨论:

    (1)若$c_{1}$在不以$z_{1}$为端点的边中出现,那么将$(x,y),(y,z_{0})$和$(z_{0},z_{1})$分别染成$c_{1},c_{2}$和$c_{1}$即可

    (2)若$c_{1}$在以$z_{1}$为端点的边中出现,假设为$(z_{1},z_{2})$,重新染$(z_{1},z_{2})$,再分类讨论……

    (具体的以此类推,即重复此过程直至出现第1种情况)

    由于是二分图,不难发现一个点不会被重复访问(否则即说明其存在两条$c_{1}$或$c_{2}$的边),因此总能够找到方案,并记边集大小为$|E|$(也即$c_{i,j}=C$的位置数),时间复杂度为$o(n|E|)$

    总复杂度为$o(n^{3})$,可以通过

    做法2:

    考虑将每一个点的度数补至$Delta$,进而求出$Delta$组完美匹配(每一组完美匹配的边对应一种颜色),然后删除补充的边即得到原图的一组方案

    第一步只需要不断在两边中各选一个度小于$Delta$的点连边即可(允许重边),第二步使用网络流来做二分图匹配(并得到方案),时间复杂度为$o(Delta n^{1.5})$(点集和边集分别大小为$n$和$nDelta$)

    关于第二步中存在$Delta$组完美匹配,可以考虑归纳证明,注意到一组完美匹配删去后即将所有点度数都减去1,而当$Delta=1$时将所有边都选上即构成完美匹配(那么$Delta>1$时显然也存在完美匹配)

    总复杂度为$o(n^{3.5})$,可能有一些卡

    (代码是做法1的)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 305
     4 #define fi first
     5 #define se second
     6 vector<pair<int,int> >v[N*N];
     7 int t,n,x,y,mx,tot,c[N][N],d[N<<1],vis[N<<1][N],ans[N][N];
     8 int main(){
     9     scanf("%d",&t);
    10     while (t--){
    11         scanf("%d",&n);
    12         mx=tot=0;
    13         for(int i=1;i<=n*n;i++)v[i].clear();
    14         for(int i=1;i<=n;i++)
    15             for(int j=1;j<=n;j++){
    16                 scanf("%d",&x);
    17                 ans[i][j]=-1;
    18                 v[x].push_back(make_pair(i,j));
    19             }
    20         for(int i=1;i<=n*n;i++){
    21             for(int j=0;j<=(n<<1);j++)d[j]=0;
    22             for(int j=0;j<v[i].size();j++)d[v[i][j].fi]++,d[v[i][j].se+n]++;
    23             for(int j=1;j<=(n<<1);j++)d[0]=max(d[0],d[j]);
    24             mx=max(mx,--d[0]);
    25             for(int j=1;j<=(n<<1);j++)
    26                 for(int k=0;k<=d[0];k++)vis[j][k]=0;
    27             for(int j=0;j<v[i].size();j++){
    28                 x=v[i][j].fi,y=v[i][j].se+n;
    29                 int c1,c2;
    30                 for(int k=0;k<=d[0];k++)
    31                     if (!vis[x][k])c1=k;
    32                 for(int k=0;k<=d[0];k++)
    33                     if (!vis[y][k])c2=k;
    34                 while (y){
    35                     if (ans[x][y-n]>=0)vis[y][ans[x][y-n]]=0;
    36                     ans[x][y-n]=c1,vis[x][c1]=y;
    37                     swap(vis[y][c1],x);
    38                     if (!x)break;
    39                     if (ans[x][y-n]>=0)vis[x][ans[x][y-n]]=0;
    40                     ans[x][y-n]=c2,vis[y][c2]=x;
    41                     swap(vis[x][c2],y);
    42                 }
    43             }
    44         }
    45         for(int i=1;i<=n;i++)
    46             for(int j=1;j<=n;j++)
    47                 if (ans[i][j])tot++;
    48         printf("%d %d
    ",mx,tot);
    49         for(int i=1;i<=n;i++)
    50             for(int j=1;j<=n;j++)
    51                 if (ans[i][j])printf("%d %d %d
    ",i,j,ans[i][j]);
    52     }
    53     return 0;
    54 }
    View Code
  • 相关阅读:
    10-JavaScript 条件语句
    9-JavaScript 比较
    8-JavaScript 运算符
    6-JavaScript 事件
    Sum Problem 重定向文件的使用
    Calculate A + B.
    Vue中computed的本质及与methods的区别
    外部文件使用django的models
    DjangoURL反向解析
    字符串格式化的方式
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15159132.html
Copyright © 2020-2023  润新知