// // // // // // // // // // // // // //

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点: 即必胜点 某玩家位于此点 只要自己无失误 则必胜

三个定理:

  1. 所有终结点都是必败点P
  2. 所有一步能走到必败点P的就是N点
  3. 通过一步操作只能到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;
}


总结:

  1. 不要瞎写一些自己都不知道对不对的优化
  2. 做题的时候注意数据范围 谨慎选择算法

——end

posted @ 2021-02-02 19:07  Blank_space  阅读(76)  评论(0)    收藏  举报
// // // // // // //