zoukankan      html  css  js  c++  java
  • Codeforces Round #270 D C B A

    谈论最激烈的莫过于D题了!

    看过的两种做法不得不ORZ,特别第二种,简直神一样!!!!!

    1th:构造最小生成树。

        我们提取所有的边出来按边排序,因为每次我们知道边的权值>0,

    之后每次把边加入集合中,不断构造,类似  kruskal算法,构造出边后

    再对每个点进行整张图的DFS求距离

    复杂度O(N^2lgN):对所有边排序的复杂度。

      1 #include<bits/stdc++.h>
      2 
      3 #define N 2222
      4 using namespace std;
      5 typedef long long ll;
      6 #define inf 0x3f3f3f
      7 int n;
      8 int f[N],vis[N];
      9 int a[N][N];
     10 
     11 struct node
     12 {
     13     int u,v,w;
     14     node(int uu,int vv,int ww):u(uu),v(vv),w(ww){}
     15 };
     16 
     17 vector<pair<int,int> > G[N];
     18 vector<node> edge;
     19 
     20 int find(int x)
     21 {if (f[x]!=x) return f[x]=find(f[x]);}
     22 
     23 int cmp(node a,node b){return a.w<b.w;}
     24 
     25 ll dis[N];
     26 void dfs(int x)
     27 {
     28    vis[x]=1;
     29  //  cout<<dis[x]<<" ";
     30    for (int i=0;i<G[x].size();i++)
     31    {
     32        int v=G[x][i].first;
     33        int w=G[x][i].second;
     34        if (vis[v]) continue;
     35        dis[v]=dis[x]+w;
     36        dfs(v);
     37    }
     38 }
     39 
     40 int solve()
     41 {
     42     for (int i=1;i<n;i++)
     43     for (int j=i+1;j<=n;j++)
     44          edge.push_back(node(i,j,a[i][j]));
     45 
     46     for (int i=1;i<=n;i++) f[i]=i;
     47 
     48     sort(edge.begin(),edge.end(),cmp);
     49     int t=edge.size();
     50     for (int i=0;i<t;i++)
     51     {
     52         int x=edge[i].u;
     53         int y=edge[i].v;
     54         int tx=find(x);
     55         int ty=find(y);
     56         if (tx!=ty)
     57         {
     58             f[tx]=ty;
     59             G[x].push_back(make_pair(y,edge[i].w));
     60             G[y].push_back(make_pair(x,edge[i].w));
     61         }
     62     }
     63 
     64 
     65     for (int i=1;i<=n;i++)
     66     {
     67         memset(vis,0,sizeof(vis));
     68         memset(dis,0,sizeof(dis));
     69         dfs(i);
     70 
     71         for (int j=1;j<=n;j++)
     72         if (dis[j]!=a[i][j])
     73         {
     74             return 0;
     75         }
     76     }
     77     return 1;
     78 }
     79 
     80 int main()
     81 {
     82 
     83    scanf("%d",&n);
     84     for (int i=1;i<=n;i++)
     85     for (int j=1;j<=n;j++)
     86       scanf("%d",&a[i][j]);
     87 
     88     for (int i=1;i<=n;i++)
     89     for (int j=1;j<=n;j++)
     90     {
     91        if (a[i][j]!=a[j][i]||i==j&&a[i][j]!=0)
     92        {
     93            puts("NO");
     94            return 0;
     95        }
     96        if (i!=j&&a[i][j]==0)
     97            {
     98             puts("NO");
     99            return 0;
    100            }
    101     }
    102 
    103  if (solve())  puts("YES");
    104  else  puts("NO");
    105  return 0;
    106 }

    代码可能更好说明思路,关键一点是:我们每次把最短的边加入集合。我们确定这是一颗最小生成树!所以加边次序是和MST是一样的。

    第二种做法不得不佩服!1

    这个特种点很难在比赛中发现啊

    关键点:我们知道一个点到其他所有点都有一条最小距离的边--假设A到其他点最小距离的点是B,A-B一定是直接连接的。假设距离是X。

               然后假设一个点C,C到B点要么比C到A点近X,要么C到A点远X。具体可以画图。

    通过这个方法可以判断数据是否合法!

    代码超级短

     1 #include<bits/stdc++.h>
     2 typedef long long ll;
     3 using namespace std;
     4 #define N 2222
     5 
     6 
     7 int a[N][N];
     8 int n;
     9 int main()
    10 {
    11     scanf("%d",&n);
    12     for (int i=1;i<=n;i++)
    13     for (int j=1;j<=n;j++)
    14     scanf("%d",&a[i][j]);
    15     
    16     //预处理判断
    17     int flag=0;
    18     for (int i=1;i<=n;i++)
    19     for (int j=1;j<=n;j++)
    20     {
    21        if (i!=j&&a[i][j]==0) flag=1;
    22        if (i==j&&a[i][j]!=0)   flag=1;
    23        if (i!=j&&a[i][j]!=a[j][i]) flag=1;
    24        }
    25        
    26        if (flag)
    27        {
    28            puts("NO");
    29            return 0;
    30         }
    31 
    32     for (int i=1;i<=n;i++)
    33     {
    34         int inf= 1900000000;//初始的值要比较大些
    35         int pos=-1;
    36         for (int j=1;j<=n;j++){
    37         if (i==j) continue;
    38         if (a[i][j]<inf)
    39         {
    40             inf =a[i][j];
    41             pos=j;
    42             }
    43         }
    44         for (int j=1;j<=n;j++)
    45         {
    46             if (i==j||j==pos) continue;
    47             if (abs(a[i][j]-a[pos][j])!=inf)
    48             {
    49                 puts("NO");
    50                 return 0;
    51             }
    52         }
    53     }
    54 
    55    puts("YES");
    56    return 0;
    57 }

    后面的基本是水体了:
    C:贪心:
    从第一的判断每次找合理值,矛盾就错误!
    B:
    我是用贪心的做法!
    想想我们最后电梯还是要回到第一层!对吧!
    也要走到最高层,当前有人想去的最高层!
    那么我们每次把前K高层的先送上去!就能满足答案最小!

     1 #define N 111111
     2 using namespace std;
     3 
     4 
     5 int a[2222];
     6 int cmp(int x,int y)
     7 {
     8     return x>y;
     9 }
    10 int main()
    11 {
    12     int n,k;
    13     cin>>n>>k;
    14     
    15     for (int i=1;i<=n;i++) cin>>a[i];
    16     sort(a+1,a+n+1,cmp);
    17     int ans=0;
    18     for (int i=1;i<=n;i+=k)
    19         ans+=(a[i]-1)*2;
    20 
    21     cout<<ans<<endl;
    22     return 0;

     复杂度O(N^2);时间600MS;这是快

    
    
  • 相关阅读:
    hdu 1166 敌兵布阵
    linux(debian)系统django配远程连接sqlserver数据库
    [机器学习] Coursera ML笔记
    UICollectionView使用方法补充(照片轮播墙)
    word中公式的排版及标题列表
    FZOJ2110: Star
    Windows 下的 Makefile 编写
    掌握VS2010调试 -- 入门指南
    Visual Studio 2010初学者的调试指南:Mastering Debugging in Visual Studio 2010
    AlphaGo:用机器学习技术古老的围棋游戏掌握AlphaGo: Mastering the ancient game of Go with Machine Learning
  • 原文地址:https://www.cnblogs.com/forgot93/p/4000850.html
Copyright © 2011-2022 走看看