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;这是快

    
    
  • 相关阅读:
    桟错误分析方法
    gstreamer调试命令
    sqlite的事务和锁,很透彻的讲解 【转】
    严重: Exception starting filter struts2 java.lang.NullPointerException (转载)
    eclipse 快捷键
    POJ 1099 Square Ice
    HDU 1013 Digital Roots
    HDU 1087 Super Jumping! Jumping! Jumping!(动态规划)
    HDU 1159 Common Subsequence
    HDU 1069 Monkey and Banana(动态规划)
  • 原文地址:https://www.cnblogs.com/forgot93/p/4000850.html
Copyright © 2011-2022 走看看