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); }