uestc 1651 Fill Numbers

题目链接:uestc 1651 Fill Numbers


这道题目确实是比较好,当时比赛的时候就一心想着高斯肖元,但是最坏的情况未知数最多为1000,而我的高斯肖元模版的时间复查度是O(n^3)几乎不可搞。。。因为如果高斯肖元的话,每个方程最多才2个未知数,一定可以得到更优的算法


把空格看作点,如果一行有 2 个空格,就在这两个空格之间连一条边,如果
列有2 个空格同理。这样最后形成的图可以分为以下几种连通块
 
1、一个孤立的点,说明这个点的值直接受所在行和所在列的约束,因此这
点可能有唯一解,也可能无解。
 
2、一条链,两个端点均为度为 1 的点,因此两个端点的值都可以通过所在
行或列唯一确定,我们从一端开始 dfs,依次求出链中每个点的值,最后判断一
下另一个端点的值是否合法即可。在这种情况下也是可能有唯一解,或者无解。  
 
3、一个环,仔细思考后可以发现,对一个环,只要存在一组特解,就一定
可以构造出无穷多组可行解,因此我们任取一点,任取一个初值开始 dfs,把环
拆成链,求出环中的一组特解,如果特解存在,则有无穷解,否则无解。
 
具体操作可以先从度为 1 的点开始 dfs,向空格填入对应的解,然后处理所
有度为0 的孤立点,最后判断有没有环,如果有环的环填入一组特解。最后统一
判断解是否合法

1、解合法&&无环    Unique
2、解合法&&有环    More than one
3、解不合法        No solution 


证明第3点其实很好证明:

  如果存在环的话,那么这个环内的定点个数就是偶数个,假如设 1 -> 2 -> 3 ->4 -> 1 是个环,而(1,2)的和值a,(2,3)和值为b,(3,4)和值为c,(4,1)和值为d, 那么只要满足

a+ c = b + d 就一定存在无穷多节,否者就无解


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

const int maxn=1010;
int n,m,a[maxn][maxn],row[maxn],col[maxn];
int x[maxn*2],y[maxn*2],degree[maxn*2];
vector<int> g[maxn*2];
bool vis[maxn*2];

int cal(int u)
{
    int i;
    for(i=0;i<m;i++)
      if(i!=y[u]&&a[x[u]][i]==-1) break;
    if(i>=m){
       int tmp=0;
       for(int j=0;j<m;j++)
         if(j!=y[u]) tmp+=a[x[u]][j];
       return row[x[u]]-tmp;
    }
    int tmp=0;
    for(i=0;i<n;i++)
      if(i!=x[u]) tmp+=a[i][y[u]];
    return col[y[u]]-tmp;
}
int Cal(int u,int v)
{
    if(x[u]==x[v]){
       int tmp=0;
       for(int i=0;i<m;i++)
         if(i!=y[u]&&i!=y[v]) tmp+=a[x[u]][i];
       return row[x[u]]-tmp;
    }
    int tmp=0;
    for(int i=0;i<n;i++)
      if(i!=x[u]&&i!=x[v]) tmp+=a[i][y[u]];
    return col[y[u]]-tmp;
}
int last,last_v;
void dfs(int u,int va)
{
    vis[u]=1;
    last=u,last_v=va;
    int sz=g[u].size();
    for(int i=0;i<sz;i++)
    {
        int v=g[u][i];
        if(!vis[v]){
           int val=Cal(u,v)-va;
           dfs(v,val);
        }
    }
}
int main()
{
    int T,ca=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);

        for(int i=0;i<n*m;i++) g[i].clear();
        for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
          scanf("%d",&a[i][j]);
        for(int i=0;i<n;i++) scanf("%d",&row[i]);
        for(int i=0;i<m;i++) scanf("%d",&col[i]);

        bool ok=1;
        for(int i=0;i<n;i++)
        {
            bool have=0;
            int tmp=0;
            for(int j=0;j<m;j++)
              if(a[i][j]==-1)  { have=1;break; }
              else tmp+=a[i][j];
            if(!have&&tmp!=row[i]) { ok=0;break; }
        }
        printf("Case #%d: ",ca++);
        if(!ok) { puts("No solution");continue; }

        for(int j=0;j<m;j++)
        {
            bool have=0;
            int tmp=0;
            for(int i=0;i<n;i++)
              if(a[i][j]==-1) {have=1;break;}
              else tmp+=a[i][j];
            if(!have&&tmp!=col[j]) { ok=0;break;}
        }
        if(!ok) { puts("No solution");continue; }

        int id=0;
        for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
          if(a[i][j]==-1) x[id]=i,y[id++]=j;

        memset(degree,0,sizeof(degree));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<id;i++)
        for(int j=i+1;j<id;j++)
          if(x[i]==x[j]||y[i]==y[j])
          {
              g[i].push_back(j);
              g[j].push_back(i);
              degree[i]++,degree[j]++;
          }

        for(int i=0;i<id;i++)
          if(!vis[i]&°ree[i]==1)
          {
              int val=cal(i);
              dfs(i,val);
              if(cal(last)!=last_v) { ok=0;break;}
          }
       if(!ok) { puts("No solution"); continue; }
       bool multi=0;
       for(int i=0;i<id;i++)
         if(!vis[i]&°ree[i]==2)
         {
             int sum=Cal(i,g[i][0]);
             vis[i]=1;
             dfs(g[i][0],sum);
             if(Cal(last,i)==last_v) multi=1;
             else ok=0;
         }
       if(!ok) puts("No solution");
       else if(ok&&multi) puts("More than one");
       else puts("Unique");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
互联网络程序设计是指在互联网上进行程序开发和设计的过程。UESTC则是我国的一所著名高校——电子科技大学。 互联网络程序设计 uestc包含了两个主要的方面:互联网络和程序设计。互联网络是指将多个计算机网络通过通信链路互相连接起来,实现信息共享和资源共享的网络系统。程序设计是指根据需求和目标,通过编写代码和设计算法,实现计算机程序的过程。 互联网络程序设计 uestc的学习内容主要包括以下几个方面: 1. 网络知识:学习互联网络的基本概念、原理和协议,如TCP/IP协议、HTTP协议等。掌握网络编程的基本技术,能够编写网络应用程序。 2. 数据通信:学习数据通信的基本原理和技术,包括数据传输的方式、数据压缩和加密等。了解网络安全和数据保护的基本知识。 3. 程序设计:学习编程语言和开发工具,如Java、C++和Python等。掌握常用的编程技巧和方法,能够设计和实现复杂的网络应用程序。 4. Web开发:学习Web开发的基本知识和技术,包括HTML、CSS、JavaScript等。能够设计和实现交互式的Web应用程序。 5. 数据库技术:学习数据库的基本原理和技术,如SQL语言和数据库管理系统。能够设计和管理数据库,实现数据的存储和检索。 通过学习互联网络程序设计 uestc,可以掌握互联网应用开发的基本技能,具备设计和实现网络应用程序的能力。这对于目前互联网行业的人才需求来说是非常重要的,也为学生提供了广阔的就业和创业机会。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值