zoukankan      html  css  js  c++  java
  • p1228

    这是一道图论呦.

    这怎么和图论相关呢?差分约束不是也看起来和图论无关么2333.

    那么本题就类似于差分约束.考虑到矩形的每一条边都有一部分露出来,那么可以m*n的用至少四个点更新每个字母的四个顶角位置.然后对于每个有顶角的字母跑它的四个边,如果有别的字母就说明这个字母再本字母之上,连一条有向边.(在这里连的话很大几率使两点间有多个边.考虑到点最多有26个,可以写一个邻接矩阵)

    这样就有了一个有向无环图,我们要做的就是按照字典序输出所有可行顺序.这个怎么弄呢?如果只输出一个的话我会维护堆后拓扑排序全部输出的话...依旧欺负它点少,我们直接上一个带dfs的回溯拓扑就好.

    我写的还是个邻接表...并且记录入度和是否有点flag.对于从'a'到'z'如果flag==1且入度为0就记录答案,flag改为1,然后dfs冲进去,对于从a到z再判断一下,记录答案,所连边sum--,然后再冲进去.如果dfs层数为n时输出return,并打扫现场.

    为什么这样子能做到字典序从小到大呢?因为每次把字母放进ans时是从A到Z的.而邻接表的遍历对然是逆字典序的,但是不影响答案啊.

    46 .
    65 A
    90 Z

    虽然字符和数字间可以这样转化,但是实际上并不需要这么严格,字符实际上就是数字.

    using namespace std;
    int i,f,t;
    char ch;
    char ans[100];
    int n,m;
    int l[100],r[100],u[100],d[100],sum[100],flag[100],a[100][100],o[100][100];
    struct node{
        int x,y,next;
    }e[10000];
    int tot,head[100];
    void add(int x,int y){
        tot++;
        e[tot].x=x;
        e[tot].y=y;
        e[tot].next=head[x];
        head[x]=tot;
    }
    void dfs(int now)
    {
        if(now==n){
            for(int j=1;j<=n;j++)
                cout<<ans[j];
            cout<<endl;
            return;
        }
        now++;
        for(int k=65;k<=90;k++)
            if(!sum[k]&&flag[k]){
                for(int j=head[k];j!=0;j=e[j].next)
                    sum[e[j].y]--;
                ans[now]=k;
                flag[k]=0;//改一下
                dfs(now);
                flag[k]=1;//打扫现场
                for(int j=head[k];j!=0;j=e[j].next)
                    sum[e[j].y]++;
            }
    }    
    int main()
    {
        cin>>n>>m;
        memset(l,127,sizeof(l));
        memset(u,127,sizeof(u));
        for(i=1;i<=n;i++)
            for(f=1;f<=m;f++){
                cin>>ch;
                a[i][f]=t=int(ch);
                l[t]=min(f,l[t]);
                r[t]=max(f,r[t]);
                u[t]=min(i,u[t]);
                d[t]=max(i,d[t]);
            }
        for(t=65;t<=90;t++){
            if(r[t]!=0){
                
                f=l[t];
                for(i=u[t];i<=d[t];i++)
                    if(a[i][f]!=t)
                        o[t][a[i][f]]=1;
                f=r[t];
                for(i=u[t];i<=d[t];i++)
                    if(a[i][f]!=t)
                        o[t][a[i][f]]=1;
                i--;
                for(f=l[t];f<=r[t];f++)
                    if(a[i][f]!=t)
                        o[t][a[i][f]]=1;
                i=u[t];
                for(f=l[t];f<=r[t];f++)
                    if(a[i][f]!=t)
                        o[t][a[i][f]]=1;
                flag[t]=1;
            }
        }
        n=0;
        for(i=65;i<=90;i++){
            for(f=65;f<=90;f++)
                if(o[i][f])
                    sum[f]++,add(i,f);//连边,统计入度
            if(flag[i])//统计总点数n
                n++;
        }
        for(i=65;i<=90;i++){
            if(!sum[i]&&flag[i]){
                for(int j=head[i];j!=0;j=e[j].next)
                    sum[e[j].y]--;
                ans[1]=i;
                flag[i]=0;
                dfs(1);//来啊快活啊
                flag[i]=1;//打扫现场
                for(int j=head[i];j!=0;j=e[j].next)
                    sum[e[j].y]++;
            }
        }
        return 0;
    }

    我可能永远也习惯不了这样子的缩进,但还是要努力学习.

    让我去吐一会...

  • 相关阅读:
    动态规划——Best Time to Buy and Sell Stock IV
    动态规划——Split Array Largest Sum
    动态规划——Burst Ballons
    动态规划——Best Time to Buy and Sell Stock III
    动态规划——Edit Distance
    动态规划——Longest Valid Parentheses
    动态规划——Valid Permutations for DI Sequence
    构建之法阅读笔记05
    构建之法阅读笔记04
    构建之法阅读笔记03
  • 原文地址:https://www.cnblogs.com/qywyt/p/9690046.html
Copyright © 2011-2022 走看看