CF 274D Lovely Matrix(拓扑排序+缩点) 个人心得

CF 274D Lovely Matrix 拓扑排序中缩点使用 个人心得

题目传送门http://codeforces.com/contest/274/status/D

题目大意:给出一个n*m的矩阵,问,是否能通过改变的顺序,使得每一都非递减,-1表示这个数未知(可以为任意数)。

解题思路:典型的拓扑排序题,但是因为各元素可以相等,而简单的拓扑排序限定了元素之间必须是一一对应,无法做到使相等的元素平行,所以这里就需要加入辅助点(冗余点)来达到允许元素平行这一目的。


最开始我遇到这个问题时,想到的是通过讲值相同的元素组与其他元素一一建立联系(下面代码中被注释掉的部分就是),这样的确可以解决一对多、多对一的问题,但是,他不能解决一对一的问题,而且操作麻烦。所以我看了别人的代码,找到了正确的解题方案。以下是我在对这种方法的理解上的心得:

  • 辅助点原理:
  • 因为:
  • 每一组相同值单位都需要同时被释放,同时可用
  • 每一组相同值单位需要被全部释放后,它的后续值单位(指向的下一个)才能被完全释放
  • 所以:
  • 对于每一轮的限制,都增加一组辅助点,其数量等于次轮中不同值的元素的数量,所以对于n*m次的入度计算,需要的辅助点数量<=n*(m+1)
  • 辅助点用来“存储”下一个要释放的元素下标和释放它所需要的先被释放的元素下标
  • 这样,每个元素之间的限制关系就不再只是一对一,而可以是一对多多对一多对多,所以就能解决在拓扑排序里,平行元素组和其他单个元素或其他平行元素组之间不能建立简单大小关系的问题
     

代码(自己写的,可能有很多不足):

#include<bits/stdc++.h>
#define M 200010
using namespace std;
vector<int> re[M];
queue<int> que;
int ro[M],n,m,t,ans[M],er[M],cc;
struct S{
    int v,x;
    bool operator < (const S t)const{
        return v<t.v;
    }
}a[M];

///原来的方法所用的topo,效率不高,但易于理解
int topo1(){
    int n=1,aim=-1;
    for(int i=1;i<=m;++i){
        for(int j=1;j<=m;++j){
            if(ro[j]==0){
                ro[j]=-1;
                aim=j;
                break;
            }
        }
        if(aim==-1)return puts("-1")*0;
        int s0=re[aim].size();
        for(int j=0;j<s0;++j){
            ro[re[aim][j]]--;
        }
        ans[n++]=aim;
        aim=-1;
    }
    return 1;
}

///用队列进行拓扑排序
int topo0(){
    for(int i=1;i<=m+cc;++i)if(!ro[i])que.push(i);
    int t0=1;
    while(!que.empty()){
        int x=que.front();
        que.pop();
        if(x<=m)ans[t0++]=x;
        for(int i=0;i<re[x].size();++i){
            int y=re[x][i];
            ro[y]--;
            if(!ro[y])que.push(y);
        }
    }
    return t0>=m;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        //memset(er,0,sizeof(er));///不可偷懒!
        for(int j=1;j<=m;++j){
            scanf("%d",&a[j].v);a[j].x=j;
        }
        sort(a+1,a+m+1);
        int sta=-1;
        for(int j=1;j<=m;++j){
            if(a[j].v==-1)continue;
			if(j==1||a[j].v!=a[j-1].v)cc++;
			re[m+cc].push_back(a[j].x);
			re[a[j].x].push_back(m+cc+1);
			ro[a[j].x]++;
			ro[m+cc+1]++;
						
/*
///这种方法不可行
//            if(a[j-1].v==-1)continue;
//            if(a[j].v==a[j-1].v){
//                if(sta<0)sta=j-1;
//                if(er[a[j-1].x]==0)continue;
//                ro[a[j].x]++;
//                re[er[a[j-1].x]].push_back(a[j].x);
//                er[a[j].x]=er[a[j-1].x];
//                continue;
//            }
//            if(sta>0){
//                for(int k=sta;k<j-1;++k){
//                    ro[a[j].x]++;
//                    re[a[k].x].push_back(a[j].x);
//                }
//                sta=-1;
//            }
//            ro[a[j].x]++;
//            re[a[j-1].x].push_back(a[j].x);
//            er[a[j].x]=a[j-1].x;
*/
        }
        cc++;
        ///必不可少,因为在无重复的元素组(有m个元素)中,需要m+1个辅助点(有一个充当了"头")
    }
    cout<<"cc: "<<cc<<endl;
    for(int i=0;i<=m+cc;++i)cout<<ro[i]<<" ";
    cout<<endl;
    if(topo0()) for(int i=1;i<=m;++i)printf("%d ",ans[i]);else puts("-1");
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值