• [CTS2019]田野(80分)


    loj嘟嘟嘟


    学完模拟退火后开始搞这道题,搞了一下午最终搞到了80分,剩下的实在不知道怎么办了……


    首先肯定是把有交点的线段划分到一个集合,然后对每一个集合求一遍凸包。
    然后两两合并,如果新的凸包的周长更小,那必定合并。
    但有可能三个或以上合并才更优,所以上述算法肯定不行。
    这时候就要模拟退火了。
    每次随机合并两个,如果更优,就合并;否则有概率合并。然后我在每一次降温之前又暴力的全扫一遍尝试两两合并。
    模拟退火跑到2.9秒,我又写了个一个乱搞算法,借鉴了当时rk1的写法,每次随机两个合并,直到剩一个凸包,然后取过程中的最优解。这个再跑到3.95秒。
    最终搞到了80。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<assert.h>
    #include<ctime>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-13;
    const db DELTA = 0.99999;
    const int maxn = 505;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    In void MYFILE()
    {
    #ifndef mrclr
      freopen("fields.in", "r", stdin);
      freopen("fields.out", "w", stdout);
    #endif
    }
    
    int n;
    struct Point
    {
      db x, y;
      Point operator + (const Point& oth)const
      {
        return (Point){x + oth.x, y + oth.y};
      }
      Point operator - (const Point& oth)const
      {
        return (Point){x - oth.x, y - oth.y};
      }
      db operator * (const Point& oth)const
      {
        return x * oth.y - y * oth.x;
      }
      friend In void swap(Point& A, Point& B)
      {
        swap(A.x, B.x), swap(A.y, B.y);
      }
      friend In db dis(Point& A, Point& B)
      {
        return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
      }
    };
    struct Line
    {
      Point A, B;
      friend In bool cross(Line a, Line b)
      {
        db ret1 = ((a.B - a.A) * (b.A - a.A)) * ((a.B - a.A) * (b.B - a.A));
        db ret2 = ((b.B - b.A) * (a.A - b.A)) * ((b.B - b.A) * (a.B - b.A));
        return ret1 < 0 && ret2 < 0;
      }
    }l[maxn];
    
    int vis[maxn], cnt = 0;
    vector<Point> v[maxn];
    db S[maxn];
    
    Point a[maxn], P;
    int tot = 0, st[maxn], top = 0;
    In bool cmp(Point A, Point B) {return (A - P) * (B - P) > 0;}
    In db calc()
    {
      int pos = 1;
      for(int i = 2; i <= tot; ++i) 
        if(a[i].x < a[pos].x || (fabs(a[i].x - a[pos].x) < eps && a[i].y < a[pos].y)) pos = i;
      if(pos ^ 1) swap(a[1], a[pos]); P = a[1];
      sort(a + 2, a + tot + 1, cmp);
      st[top = 1] = 1;
      for(int i = 2; i <= tot; ++i)
        {
          while(top > 1 && (a[i] - a[st[top - 1]]) * (a[st[top]] - a[st[top - 1]]) > 0) --top;
          st[++top] = i;
        }
      st[top + 1] = st[1];
      db ret = 0;
      for(int i = 1; i <= top; ++i) ret += dis(a[st[i]], a[st[i + 1]]);
      return ret;
    }
    
    In db TIME() {return 1.0 * clock() / CLOCKS_PER_SEC;}
    
    vector<Point> v2[maxn];
    db S2[maxn], sum = 0, ans = 0;
    int id[maxn], cnt2 = 0;
    In void HIA()
    {
      db T = n <= 60 ? 1000000000 : 10000000, ans2 = sum; cnt2 = 0;
      for(int i = 1; i <= cnt; ++i) if(vis[i] == i) id[++cnt2] = i;
      while(T > eps && cnt2 > 1)
        {
          if(TIME() > 2.8) return;
          int x = rand() % cnt2 + 1, y = rand() % cnt2 + 1;
          while(x == y) y = rand() % cnt2 + 1;
          if(x > y) swap(x, y);
          tot = 0; 
          for(int i = 0; i < (int)v2[id[x]].size(); ++i) a[++tot] = v2[id[x]][i];
          for(int i = 0; i < (int)v2[id[y]].size(); ++i) a[++tot] = v2[id[y]][i];
          db tp = calc(), del = tp - S2[id[x]] - S2[id[y]];
          if(del < 0 || exp(-del / T) * RAND_MAX > rand())
    	{
    	  ans2 =  ans2 - S2[id[x]] - S2[id[y]] + tp;
    	  ans = min(ans, ans2);
    	  S2[id[x]] = tp;
    	  for(int i = 0; i < (int)v2[id[y]].size(); ++i) v2[id[x]].push_back(v2[id[y]][i]);
    	  for(int i = y + 1; i <= cnt2; ++i) id[i - 1] = id[i];
    	  --cnt2;
    	}
          for(int i = x + 1; i <= cnt2; ++i)
    	{
    	  if(TIME() > 2.8) return;
    	  tot = 0;
    	  for(int j = 0; j < (int)v2[id[x]].size(); ++j) a[++tot] = v2[id[x]][j];
    	  for(int j = 0; j < (int)v2[id[i]].size(); ++j) a[++tot] = v2[id[i]][j];
    	  db tp = calc();
    	  if(tp < S2[id[x]] + S2[id[i]])
    	    {
    	      ans2 =  ans2 - S2[id[x]] - S2[id[i]] + tp;
    	      ans = min(ans, ans2);
    	      S2[id[x]] = tp;
    	      for(int j = 0; j < (int)v2[id[i]].size(); ++j) v2[id[x]].push_back(v2[id[i]][j]);
    	      for(int j = i + 1; j <= cnt2; ++j) id[j - 1] = id[j];
    	      --cnt2;	      
    	    }
    	}
          T *= DELTA;
        }
    }
    In void HIA2()
    {
      db ans2 = sum; cnt2 = 0;
      for(int i = 1; i <= cnt; ++i) if(vis[i] == i) id[++cnt2] = i;
      while(cnt2 > 1)
        {
          if(TIME() > 3.95) return;
          int x = rand() % cnt2 + 1, y = rand() % cnt2 + 1;
          while(x == y) y = rand() % cnt2 + 1;
          if(x > y) swap(x, y);
          tot = 0; 
          for(int i = 0; i < (int)v2[id[x]].size(); ++i) a[++tot] = v2[id[x]][i];
          for(int i = 0; i < (int)v2[id[y]].size(); ++i) a[++tot] = v2[id[y]][i];
          db tp = calc();
          ans2 =  ans2 - S2[id[x]] - S2[id[y]] + tp;
          ans = min(ans, ans2);
          S2[id[x]] = tp;
          for(int i = 0; i < (int)v2[id[y]].size(); ++i) v2[id[x]].push_back(v2[id[y]][i]);
          for(int i = y + 1; i <= cnt2; ++i) id[i - 1] = id[i];
          --cnt2;
        }
    }
    
    int main()
    {
      //MYFILE();
      srand(20010613);
      n = read();
      for(int i = 1; i <= n; ++i)
        {
          Point A, B;
          A.x = read(), A.y = read(), B.x = read(), B.y = read();
          l[i] = (Line){A, B};
        }
      for(int i = 1; i <= n; ++i)
        if(!vis[i])
          {
    	vis[i] = 1; ++cnt;
    	v[cnt].push_back(l[i].A), v[cnt].push_back(l[i].B);
    	for(int j = i + 1; j <= n; ++j)
    	  if(!vis[j] && cross(l[i], l[j]))
    	    {
    	      vis[j] = 1;
    	      v[cnt].push_back(l[j].A), v[cnt].push_back(l[j].B);
    	    }
          }
      for(int i = 1; i <= cnt; ++i)
        {
          tot = 0;
          for(int j = 0; j < (int)v[i].size(); ++j) a[++tot] = v[i][j];
          S[i] = calc();
        }
      Mem(vis, 0);
      for(int i = 1; i <= cnt; ++i) if(!vis[i])
        {
          vis[i] = i;
          for(int j = i + 1; j <= cnt; ++j) if(!vis[j])
    	{
    	  tot = 0; db tp;
    	  for(int k = 0; k < (int)v[i].size(); ++k) a[++tot] = v[i][k];
    	  for(int k = 0; k < (int)v[j].size(); ++k) a[++tot] = v[j][k];
    	  if((tp = calc()) < S[i] + S[j])
    	    {
    	      S[i] = tp; vis[j] = i;
    	      for(int k = 0; k < (int)v[j].size(); ++k) v[i].push_back(v[j][k]);
    	    }
    	}
          ans += S[i], sum += S[i];
        }
      while(TIME() < 2.9)
        {
          for(int i = 1; i <= cnt; ++i)
    	{
    	  v2[i].clear(); S2[i] = S[i];
    	  for(int j = 0; j < (int)v[i].size(); ++j) v2[i].push_back(v[i][j]);
    	}
          HIA();
        }
      while(TIME() < 3.95)
        {
          for(int i = 1; i <= cnt; ++i)
    	{
    	  v2[i].clear(); S2[i] = S[i];
    	  for(int j = 0; j < (int)v[i].size(); ++j) v2[i].push_back(v[i][j]);
    	}
          HIA2();
        }  
      printf("%.8lf
    ", ans);
      return 0;
    }
    
  • 相关阅读:
    String Kernel SVM
    基因组印记
    用Js的eval解析JSON中的注意点
    struts2中<s:select>标签的使用
    如何在Linux中使用cron命令
    怎样解决MySQL数据库主从复制延迟的问题
    PMON failed to acquire latch, see PMON dump
    java中对List中对象排序实现
    C语言typedef关键字
    企业级内部信息统一搜索解决方案
  • 原文地址:https://www.cnblogs.com/mrclr/p/10879290.html
Copyright © 2020-2023  润新知