Topoi(一个经常会炸的网站)

本题提交链接

很久以前的题目了, 刚开了博客,来写一波题解

先看一波提交记录:

调了好几天QAQ

唉! 要是这些高手里有我估计直接 输出1 就AC了

算法

DFS + 优化剪枝(用了一点状态压缩)

剪枝

1:求最小值很容易向导最优化剪枝

if(ws>=ans) return;  //剪枝 1:最优化剪枝 

2:若一个高手会做的题有另一个高手都会做,则这个高手没有用

for(int i=1;i<=w;i++)
for(int j=1;j<i;j++)
{;
if((a[i].sn|a[j].sn)==a[j].sn) {kk[i]=1; break;} //kk表示这个高手有没有用
//剪枝 2:若这个高手会做的题有另一个人全会做,则是废物,去掉没有用的高手 (核心剪枝)
}

3:若有一个题只有一个高手能做,则将这个高手“特招”

for(int i=1;i<=w;i++)
for(int j=1;j<i;j++)
{;
if((a[i].sn|a[j].sn)==a[j].sn) {kk[i]=1; break;} //kk表示这个高手有没有用
//剪枝 2:若这个高手会做的题有另一个人全会做,则是废物,去掉没有用的高手 (核心剪枝)
}

顺序性优化:将做题多的高手排在前面(也许没用)

bool cmp(node x,node y){return x.sum>y.sum;}
sort(a+1,a+n+1,cmp); //顺序性优化: 按会做的题数排序

加上这些优化在top上大概200多ms(第二次AC记录),应该还有其他优化,但因为太ruo想不出来

这题用二进制表示状态好像多此一举

最后,附上完整代码(有点小长)

打注释都打了半个多小时QAQ

代码

#include <bits/stdc++.h>
using namespace std;
int n,w,ans=1e9,tt;//tt记录特招人数
bool k[66],kk[66],vis[66]; //k记录是否“特招”,kk记录有木有用,vis标记访问
struct node{
long long sn,sum;
int p[66];
}a[66]; //p数组记录每个高手能做的题,sn记录状态,sum记录题数,
long long num[66],q[66][66],s[66],ss[66];
//q记录每个题能做的高手,s和ss记录每个题能做的人数(有点重复了),num记录每个题的二进制,
bool cmp(node x,node y){return x.sum>y.sum;}
void find(int x,int ws,long long ssum) //x表示当前题号, ws表示高手数, ssum用二进制存储状态
{
if(ws>=ans) return; //剪枝 1:最优化剪枝
if(x>n) {ans=ws; return;} //结束条件, 更新答案
if(((ssum>>(x-1))&1==1)) {find(x+1,ws,ssum); return;} //如果这题已做,往后搜索
for(int i=1;i<=s[x];i++)
{
if(k[q[x][i]]) continue; //判断这个高手是不是 “特招”的
int tmp=q[x][i];
if(vis[tmp]) continue; //如果这个高手已经用过了
vis[tmp]=1;
find(x+1,ws+1,ssum|a[tmp].sn); //一定要用 | 运算,防止重复
vis[tmp]=0;
}
return;
}
int main()
{
scanf("%d%d",&n,&w);
num[1]=1;
for(int i=2;i<=n;i++) num[i]=num[i-1]<<1; //用2进制来表示状态
for(int i=1;i<=w;i++)
{
int x;
scanf("%d",&x);
for(int j=1;j<=x;j++)
{
int y;
scanf("%d",&y);
s[y]++;
if((a[i].sn|num[y])!=a[i].sn) //注意这里要用 | 运算,判断这题有没有出现过
a[i].sum++,a[i].p[a[i].sum]=y; //存储每个高手能做的题
a[i].sn=a[i].sn|num[y]; //更新状态
}
}
sort(a+1,a+n+1,cmp); //顺序性优化: 按会做的题数排序
for(int i=1;i<=w;i++)
for(int j=1;j<i;j++)
{
// if(i==j||kk[j]) continue;
if((a[i].sn|a[j].sn)==a[j].sn) {kk[i]=1; break;} //kk表示这个高手有没有用
//剪枝 2:若这个高手会做的题有另一个人全会做,则是废物,去掉没有用的高手 (核心剪枝)
}
long long ttmp=0;
for(int i=1;i<=w;i++)
{
if(kk[i]) continue; //直接过滤废物高手
for(int j=1;j<=a[i].sum;j++)
{
int tmp=a[i].p[j];
q[tmp][++ss[tmp]]=i;
}
}
//记录能做每个题的高手
for(int i=1;i<=n;i++)
{
if(s[i]==1&&!k[q[i][1]]) //判断第i题是不是只有一个高手会做
{
tt++;
//printf("%d\n",q[i][1]);
int tmp=q[i][1];
ttmp=ttmp|a[tmp].sn; //ttmp记录初始的搜索状态
k[tmp]=1; //标记这个高手不用考虑
}
} //剪枝 3:若有一个题只有一个高手会做,将他“特招”进来 (这个剪枝收益蛮大的)
find(1,0,ttmp);
printf("%d",ans+tt); //注意不要忘了加上“特招”人数
return 0;
}

Topoi 测验1301, 问题C: 1959: 解题 解题报告的更多相关文章

  1. TOPOI 测验1320, 问题C: 4410: [CF41D]Pawn 解题报告

    题目链接 题目大意 在一个树阵中按一定走法取一些树,使和最大且被 k+1整除 解题思路 类似一个数塔问题 因为最后的结果要被 k+1 整除,所以可以记录到每一个点  对 k+1 取余结果不同的最优解( ...

  2. 洛谷 P4397 [JLOI2014]聪明的燕姿 / TOPOI 测验1315, 问题E: 1935: 聪明的燕姿 解题报告

    题目链接 : 1. 洛谷 2.topoi . 大致题意:输入一个数s,找出所有约数和为s的数 关于一个数的约数和求法: 一个>1的整数可以被分解为多个 质数 的乘方,设数 s = p1k1 *  ...

  3. HDU 3791二叉搜索树解题(解题报告)

    1.题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3791 2.参考解题 http://blog.csdn.net/u013447865/articl ...

  4. 怎样解题 --解题表(how to solve it)

    <怎样解题> 美.波利亚 下面是来自书中的解题表: 理解题目 第一 理解题目 你必须理解题目 未知量是什么?已知数据是什么?条件是什么? 条件有可能满足吗?条件是否可以确定未适量?或者它不 ...

  5. CodeForces 701C They Are Everywhere (滑动窗口)

    题目链接:http://codeforces.com/problemset/problem/701/C 题意:找到字符串中能包含所有元素的最短字符串长度. 利用“滑动窗口”解题 解题思路: 1. 遍历 ...

  6. 【一天一道LeetCode】#63. Unique Paths II

    一天一道LeetCode (一)题目 Follow up for "Unique Paths": Now consider if some obstacles are added ...

  7. 【一天一道LeetCode】#27. Remove Element

    一天一道LeetCode系列 (一)题目 Given an array and a value, remove all instances of that value in place and ret ...

  8. 【一天一道LeetCode】#26. Remove Duplicates from Sorted Array

    一天一道LeetCode系列 (一)题目 Given a sorted array, remove the duplicates in place such that each element app ...

  9. LeetCode7-ReverseInteger

    LeetCode7-ReverseInteger LeetCodeeasyOverflow 题目 题目所在链接为 LeetCode-7:ReverseInteger 题目描述 给出一个32位的有符号整 ...

随机推荐

  1. rabbitmq-交换机

    四种交换机: direct fanout topic headers http://www.jianshu.com/p/469f4608ce5d

  2. 【leetcode刷题笔记】Populating Next Right Pointers in Each Node II

    What if the given tree could be any binary tree? Would your previous solution still work? Note: You ...

  3. 【遍历二叉树】12往二叉树中添加层次链表的信息【Populating Next Right Pointers in Each Node II】

    本质上是二叉树的层次遍历,遍历层次的过程当中把next指针加上去. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ...

  4. FJOI2016 神秘数

    题目大意 给定长为$N$一个序列,每次询问一个区间,求最小的不能表示为由区间内若干个(可以是$0$个)数的和的非负整数. 考虑一个可重集合$S$,设抽取$S$中若干个数相加无法得到的最小非负整数为$A ...

  5. HDU5446 Unknown Treasure(组合数膜合数-->Lucas+中国剩余定理)

    >On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown ...

  6. AtCoder Grand Contest 015 题解

    A - A+...+B Problem 常识 Problem Statement Snuke has N integers. Among them, the smallest is A, and th ...

  7. 系列文章--突袭HTML5之Javascript

    突袭HTML5之Javascript API扩展5 - 其他扩展 突袭HTML5之Javascript API扩展4 - 拖拽 突袭HTML5之Javascript API扩展3 - 本地存储 突袭H ...

  8. 51nod 1301 集合异或和——异或dp

    题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1301 好题!看了TJ才会. 因为是不可重集合,所以当然有前 i 个 ...

  9. NorthSJ项目零碎知识点

    1 div显示纵向滚动条: <div style="overflow-y:auto;overflow-x:hidden;"></div> 2 FineUI的 ...

  10. HDOJ1242(延时迷宫BFS+优先队列)

    Rescue Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...