UVa12726 one Friend at a Time (位 广搜)

题目链接:UVa12726

是个PDF,不好复制进来。

大意:有个人要追个妹子,想加妹子QQ,但是不知道谁规定的,玩QQ的人要加好友必须先要有至少k个共同好友。共有N个人玩QQ,编号为1到N,1是男主,N是妹子。有M个初始好友关系,求男主最少要加多少个人才能有资格加妹子,或者永远加不到妹子。

题解:

最少加多少个人加到妹子,可以想到广搜,状态是男主的加好友情况。但广搜却不能一个人只进队一次,因为从不同的路径加到这个人,结果是不同的,让我们来看看这个情况:

N=8,M=11,K=2,男主需要加到6,再加到7,才能加到女主;但如果宽搜时每次加第i个新好友的情况只进队一次,则男主会同时加到6和7,然后从加6的情况或者加7的情况都加不到女主,又不能从6跳到7或者从7跳到6,因为他们已经进过队了,这样就逗乐。

但是广搜不剪枝会超时,各种各样的路线搞出来的情况还是很多的。所以我们要根据状态来,状态是男主的加好友情况(和哪些人是好友,因为只有20个人玩QQ,可以用一个int的20个二进制位来存),dis[x]记录状态x的走过的距离,如果再次走到状态x时,距离不小于上次的距离,则不用再进这个状态了。

我用的20个bool来存的状态,结果比全用位的慢0.5s,大概我转成int来操作dis[]的时候耗时太多。

代码:

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<map>
  8 #include<set>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
 12 #define ll __int64
 13 #define usint unsigned int
 14 #define mz(array) memset(array, 0, sizeof(array))
 15 #define minf(array) memset(array, 0x3f, sizeof(array))
 16 #define REP(i,n) for(int i=0;i<(n);i++)
 17 #define FOR(i,x,n) for(int i=(x);i<=(n);i++)
 18 #define RD(x) scanf("%d",&x)
 19 #define RD2(x,y) scanf("%d%d",&x,&y)
 20 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
 21 #define WN(x) printf("%d\n",x);
 22 #define RE  freopen("D.in","r",stdin)
 23 #define WE  freopen("1.out","w",stdout)
 24
 25 const int maxn=20;
 26
 27 struct arr{
 28     bool a[maxn+1];
 29     int dis;
 30 }a[maxn];
 31
 32 int n,m,k;
 33 int dis[1<<maxn];
 34
 35 int atox(arr b)
 36 {
 37     int re=0;
 38     for(int i=1;i<=n;i++)
 39         re=(re<<1)|b.a[i];
 40     return re;
 41 }
 42
 43 int count_same(int x,int y)
 44 {
 45     int cnt=0;
 46     for(int i=1;i<=n;i++)
 47         if(a[x].a[i] && a[y].a[i])cnt++;
 48     return cnt;
 49 }
 50
 51 int gank()
 52 {
 53     int i;
 54     if(a[1].a[n])return 0;
 55     queue<arr>q;
 56     a[1].dis=0;
 57     q.push(a[1]);
 58     while(!q.empty())
 59     {
 60         a[1]=q.front();
 61         q.pop();
 62         for(i=2;i<=n;i++)
 63         {
 64             if(!a[1].a[i] && count_same(1,i)>=k)
 65             {
 66                 arr next=a[1];
 67                 next.a[i]=1;
 68                 next.dis++;
 69                 if(dis[atox(next)]<=next.dis)continue;
 70                 if(i==n) return a[1].dis;
 71                 q.push(next);
 72             }
 73         }
 74     }
 75     return -1;
 76 }
 77
 78 int main()
 79 {
 80     int cas=1,i,T;
 81     scanf("%d",&T);
 82     while(T--)
 83     {
 84         RD3(n,m,k);
 85         for(i=1;i<=n;i++)
 86             memset(a[i].a,0,sizeof(a[i].a));
 87         for(i=1;i<=m;i++)
 88         {
 89             int u,v;
 90             RD2(u,v);
 91             a[u].a[v]=1;
 92             a[v].a[u]=1;
 93         }
 94         for(i=1;i<=n;i++)
 95         {
 96             a[i].a[i]=1;
 97         }
 98         memset(dis,0x3f,sizeof(dis));
 99         dis[atox(a[1])]=0;
100         printf("Case #%d: %d\n",cas++,gank());
101     }
102     return 0;
103 }

UVa12726 one Friend at a Time (位 广搜)

时间: 2025-01-04 15:27:21

UVa12726 one Friend at a Time (位 广搜)的相关文章

hdu1241详解 Java广搜搞定

import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { int m = sc.nextInt();//输入地图的行数 int n = sc.nextInt();//输入地图的列数 if (m == 0) {//若m=0则退出程序 break; } // 初始化图

广搜+打表 POJ 1426 Find The Multiple

POJ 1426   Find The Multiple Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 25734   Accepted: 10613   Special Judge Description Given a positive integer n, write a program to find out a nonzero multiple m of n whose decimal representati

Sicily 1151 解题报告(魔板,广搜)

      I.     原题中文大意 魔板由2*4个方块组成,用1到8的数字表示不同的块. 其初始状态是 1 2 3 4 8 7 6 5 对魔板可进行三种基本操作,这三种基本操作,可将任一种状态装换成另一种状态. A (上下行互换) B (行循环右移一格) C (中间四块顺时针转90) 8 7 6 5 1 2 3 4 4 1 2 3 5 8 7 6 1 7 2 4 8 6 3 5 II.       算法思想及解题用到的主要数据结构 广度优先搜索,已搜索过的节点不再进行记录,保证第一个找到的解

深搜和广搜

先说说这个神秘的深搜: 前几天我心中的大牛给我讲了深搜感觉还是挺简单的,可大牛告诉我深搜深搜深的让你不知道怎么搜 我们也是从一道题来看:n的全排列 比如说3的全排列 123 213 321 这就是全排列   在没学过深搜的时候我们会用for循环来做这道题 但是如果n很大的时候就不行了 所以我们就一定要深搜了 其实在我看来深搜和递归是亲兄弟 深搜就是递归的加强版 我先写一个简单的dfs(深搜)函数的代码 #include<stdio.h> int dfs(int x) { if(x > n

poj 3126 prime path 简单广搜

http://poj.org/problem?id=3126 题意:给你两个四位数a,b,从a开始    每次只能改变上一次数的其中一位,问至少需要几步才能得到b 分析:求最小路   典型的广搜   表面上是    40入口的bfs   但是除去有的数不是素数   入口数远小于40 可以写一个  判断一个数是否为素数的函数  , 每次去 调用 判断一个数是否要进队列 也可以 事先打一个素数表  这样会快点 注意:output  :either with a number stating the

双向广搜

双向广搜 (2011-08-31 16:45:24)   Eight    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 讲到双向广搜,那就不能不讲经典的八数码问题,有人说不做此题人生不完整 . 所谓双向广搜,就是初始结点向目标结点和目标结点向初始结点同时扩展,直至在两个扩展方向上出现同一个结点,搜索结束.它适用的问题是,扩展结点较多,而目标结点又处在深沉,如果采用单纯的广搜解题,搜索量巨大,搜索速度慢是可想而知的,同时往往也会出现内存空

POJ 3126 Prime Path( 广搜 )

Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12974   Accepted: 7342 Description The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change the four-dig

POJ 1426 Find The Multiple (广搜)

Find The Multiple Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20235   Accepted: 8203   Special Judge Description Given a positive integer n, write a program to find out a nonzero multiple m of n whose decimal representation contains

Diablo(广搜)

Diablo Time Limit: 1000 MS Memory Limit: 65536 K Total Submit: 43(22 users) Total Accepted: 24(21 users) Rating: Special Judge: No Description Diablo是地狱中的三大魔王之一,有着非常强大的破坏力,Diablo期望着可以将一切都投入到地狱之中.为了不让Diablo的计划得逞,一位英雄决定挺身而出,试图击败Diablo.DIablo喜欢把眼前的区域变成一