USACO 1.3 warmhole

一道黄题刚了三天,把数据答案记错也是没谁了

从这道题还是看出我很多不足的,果然做黄题还是有意义

地址:https://www.luogu.org/problemnew/show/P1444

一开始我想直接建图找环,后来发现这是不行的,这是一个既有有向边又有无向边的图,直接找环很麻烦

稍加分析后发现,从一个点,如果上一次我是从虫洞走来的,这次我只能步行;如果我是步行来的,这次我必然走虫洞

因此,要把虫洞和步行分开存,对于每两个点i,j如果其y坐标相等则连一条有向边,然后枚举虫洞的匹配情况,最后在枚举完成后进行判环,如下:

令to[i]为步行到的点,con[i]为i的虫洞,则位于i,要先走到to[i],再走向to[i]的虫洞,即i = con[to[i]],记录instack判环即可

但是还有一个问题:如果有多个点的y都相同,这时是不能盲目连边的

因此,将点按y坐标排序,y相同时按x排序,对于一个点i,如果i和i +1的y相同,则在i和i + 1间连,这样能保证不会出现例如最小和第三小的点间连边的情况(而这本来是不可能的)

以上,就做出了这道题

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
inline ll read()
{
  ll ans = 0,op = 1;
  char ch = getchar();
  while(ch < '0' || ch > '9')
    {
      if(ch == '-') op = -1;
      ch = getchar();
    }
  while(ch >= '0' && ch <= '9')
    {
      (ans *= 10) += ch - '0';
      ch = getchar();
    }
  return ans * op;
}
int n;
struct node
{
  ll x,y;
}a[20];
bool cmp(const node &a,const node &b)
{
  return a.y < b.y || (a.y == b.y && a.x < b.x);
}
int con[101],to[101];
int ans = 0;
bool vis[1001];
bool instack[1001];
bool flag = 0;
bool dfs_cy(int u)
{
  while(to[u])
    {
      if(instack[u]) return 1;
      instack[u] = 1;
      u = con[to[u]];
    }
  return 0;
}
void dfs(int k)
{
  if(k > n)
    {
      flag = 0;
      for(int i = 1;i <= n && !flag;i++) memset(instack,0,sizeof(instack)),flag |= dfs_cy(i);
      ans += flag;
    }
  if(con[k]) dfs(k + 1);
  else
    {
  for(int i = k + 1;i <= n;i++)
    {
    if(!con[i])
      {
    con[i] = k,con[k] = i;
    dfs(k + 1);
    con[i] = con[k] = 0;
      }
    }
    }
}
bool ok[101][101];
int main()
{
  n = read();
  for(int i = 1;i <= n;i++) a[i].x = read(),a[i].y = read();
  sort(a + 1,a + 1 + n,cmp);
  for(int i = 1;i <= n;i++) if(a[i].y == a[i + 1].y) to[i] = i + 1;
  //for(int i = 1;i <= n;i++) printf("%d ",to[i]);
  //cout << endl;
  dfs(1);
  printf("%d",ans);
}

 

posted on 2018-11-17 09:43  L_M_A  阅读(136)  评论(0编辑  收藏  举报

导航