1. 可达性统计
时间:半小时之内
https://www.acwing.com/problem/content/166/
思路:
- 暴力,每一个点做一次dfs探查能到达多少个点
- 拓扑排序加bitset记录能到达的点。A能到达B点,则A所能到达的点就是A这个点本身并上B所能到达的点,同理,B所能到达的点则为B这个点并上与B相连的点所能到达的点,如果一个点出度为0,该点只能到达它本身。因此,只需要做个拓扑排序(将所有边反向),第一次找出度为0的点,这些点可以直接确定所能到达的点,接着再继续更新与这些点相邻的点,为了便于直接查找哪些点到达这个出度为0的点,所以处理之前将所有边反向。
代码示例:
#include <iostream>
#include <bitset>
#include <vector>
#include <queue>
using namespace std;
struct Edge{
int to;
Edge(int _v){to = _v;}
};
typedef struct Edge Edge;
int n, m;
int deg[30005];
bitset<30005> bs[30005];
vector<Edge> revg[30005];
void top_sort(){
queue<int> que;
for(int i = 1; i <= n; i++){
if(deg[i] == 0){
que.push(i);
}
}
while(!que.empty()){
int t = que.front();
que.pop();
bs[t].set(t, 1);
for(int i = 0; i < revg[t].size(); i++){
Edge e = revg[t][i];
bs[e.to] |= bs[t];
deg[e.to]--;
if(deg[e.to] == 0){
que.push(e.to);
}
}
}
}
int main(){
int a, b;
cin>>n>>m;
for(int i = 0; i < m; i++){
cin>>a>>b;
revg[b].push_back(Edge(a));
deg[a]++;
}
top_sort();
for(int i = 1; i <= n; i++){
cout<<bs[i].count()<<endl;
}
return 0;
}
2. 小猫爬山
https://www.acwing.com/problem/content/167/
思路:
- 贪心,每次从第一个缆车开始找,能放的进就直接放(WA,过不了, 比如5 5 1 2 3 4 5这组数据)
- 纯暴力,找出所有可能,TLE
- 暴力+剪枝,AC。当次数超过答案,剪枝;当新加上一个缆车,剪枝,不需要再考虑放到更后面的缆车。
代码实现:
#include <iostream>
using namespace std;
int n, w;
int cats[20], cars[20];
int ans = 0x3f3f3f3f;
void dfs(int catpos, int cnt){
// 不可能比最小值更小,返回
if(cnt >= ans)return;
if(catpos >= n){
ans = min(ans, cnt);
return;
}
for(int i = 0; i < n; i++){
if(w - cars[i] >= cats[catpos]){
// 有新加入缆车,那么需要的缆车数应为到当前缆车之前的车,否则数量不变
int tcnt;
if(cars[i] == 0)tcnt = i + 1;
else tcnt = cnt;
cars[i] += cats[catpos];
dfs(catpos + 1, tcnt);
cars[i] -= cats[catpos];
}
// 加入了新车,不考虑后边的缆车
if(cars[i] == 0)break;
}
}
int main(){
cin>>n>>w;
for(int i = 0; i < n; i++){
cin>>cats[i];
}
dfs(0, n);
cout<<ans;
return 0;
}