2.2 图论专场 题解报告
2.2 校测 图论专场
前言:
T1 60 Pts
T2 10 Pts
T3 0 Pts
总分: 70 Pts
是我菜了
T1 想到了给公交车建边 但是我确实建了边 对公交车所经过的每一个点都建了边 空间爆炸
T2 我写优化 我有病
T3 博弈论没看过 看不懂样例
大概就是这样
T1 公交车
题目:

思路:
以公交车为一个点 向所有能停靠点建边 上车的边权为费用 下车的边权为 0 跑一边最短路即可
这个题后面的点由于数据过大好像把SPFA干掉了 建议写 dijkstra
另:
关于 孙土蛋 T掉的问题 我也不知道为什么
我后来改的代码过了 但是孙土蛋的 T掉了
code:
/*
Time: 2.2
Worker: Blank_space
Source: 图论专场 T1
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define int long long
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, m, k, s, dis[C];
struct edge {int v, w, nxt;}e[C];
int head[C], ecnt;
struct node {
int d, dis;
bool operator < (const node & x )const {return dis > x.dis;}
};
bool vis[C];
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void add_edge(int u, int v, int w) {e[++ecnt] = (edge){v, w, head[u]}; head[u] = ecnt;}
/*----------------------------------------函数*/
signed main()
{
freopen("transprt.in", "r", stdin);
freopen("transprt.out", "w", stdout);
n = read(); m = read(); k = read(); s = read();
memset(dis, 0x3f, sizeof dis);
for(int i = 1; i <= m; i++)
{
int x = read(), y = read(), z = read();
add_edge(x, y, z); add_edge(y, x, z);
}
for(int i = 1; i <= k; i++)
{
int b = read(), t = read();
for(int j = 1; j <= t; j++)
{
int x = read();
add_edge(x, i + n, b);
add_edge(i + n, x, 0);
}
}
priority_queue <node> q;
q.push((node){s, 0}); dis[s] = 0;
while(!q.empty())
{
node h = q.top(); q.pop();
int u = h.d;
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v, w = e[i].w;
if(h.dis > dis[v]) continue;
if(dis[v] > dis[u] + w) dis[v] = dis[u] + w, q.push((node){v, dis[v]});
}
}
for(int i = 1; i <= n; i++) printf("%lld ", dis[i]);
return 0;
}
T2 灌溉
题目:

思路:
没有思路
只要不是傻的和我一下加一些稀奇古怪的优化的都能过
code:
/*
Time: 2.2
Worker: Blank_space
Source: 图论专场 T2
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define int long long
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, val[310], ans, fa[310], cnt;
bool vis[310];
struct edge {
int u, v, w, nxt;
bool operator < (const edge & x)const {return w == x.w ? v < x.v : w < x.w;}
}e[C];
int head[310], ecnt;
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
void add_edge(int u, int v, int w) {e[++ecnt] = (edge){u, v, w, head[u]}; head[u] = ecnt;}
/*----------------------------------------函数*/
signed main()
{
freopen("irrigate.in", "r", stdin);
freopen("irrigate.out", "w", stdout);
n = read();
for(int i = 1; i <= n; i++) val[i] = read(), fa[i] = i;
fa[n + 1] = n + 1;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
int x = read();
if(i == j) continue;
add_edge(i, j, x);
}
}
for(int i = 1; i <= n; i++) add_edge(n + 1, i, val[i]), add_edge(i, n + 1, val[i]);
sort(e + 1, e + 1 + ecnt);
for(int i = 1; i <= ecnt; i ++)
{
int u = e[i].u, v = e[i].v, w = e[i].w;
int x = find(u), y = find(v);
if(x != y) ans += w, fa[y] = x, cnt++;
}
printf("%lld", ans);
fclose(stdin);
fclose(stdout);
return 0;
}
T3 对决
题目:

思路:
感觉这个题和博弈论没有太大的关系 就是用到了几个结论 一会再说...
$ N/P $ 分析:
P点: 即必败点 某玩家位于此点 只要对方无失误 则必败
N点: 即必胜点 某玩家位于此点 只要自己无失误 则必胜
三个定理:
- 所有终结点都是必败点P
- 所有一步能走到必败点P的就是N点
- 通过一步操作只能到N点的就是P点
关于这个题目 最终局的状态已经给出 只用到后两个就好了
这样思路就很明确了 以出度跑出拓扑序 按照拓扑序注意检查即可
code:
/*
Time: 2.2
Worker: Blank_space
Source: 图论专场 T3
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, m, a[B], out[B], q[B], t;
bool vis[B];
vector <int> e[B], _e[B];
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
/*----------------------------------------函数*/
int main()
{
freopen("duel.in", "r", stdin);
freopen("duel.out", "w", stdout);
n = read(); m = read();
for(int i = 1; i <= m; i++)
{
int x = read(), y = read();
e[x].push_back(y); out[x]++;
_e[y].push_back(x);
}
for(int i = 1; i <= n; i++) if(!out[i]) q[++t] = i, a[i] = read(), vis[i] = 1;
for(int j = 1; j <= n; j++)
{
int u = q[j];
for(int i = 0; i < _e[u].size(); i++)
{
int v = _e[u][i];
if(!--out[v]) q[++t] = v;
}
}
for(int j = 1; j <= n; j++)
{
int u = q[j];
if(vis[u]) continue;
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i];
if(!a[v]) {a[u] = 1; break;}
}
}
for(int i = 1; i <= n; i++)
if(a[i]) puts("First");
else puts("Last");
return 0;
}
总结:
- 不要瞎写一些自己都不知道对不对的优化
- 做题的时候注意数据范围 谨慎选择算法
——end

浙公网安备 33010602011771号