题目链接

题意:

给出一个无向图,类似三角形的样子,然后给出边的权值,问找一条从第一个点到最后一个点的路径,要求每一条边只能走一次,并且权值和最大,点可以重复走。

思路:

首先观察这个图可以发现,所有的点的度数都是偶数。然后由每条边只能走一次知道,这个是和欧拉路相关的,是欧拉道路,不是欧拉回路,因为题目要求是从一个点到另一个点。但是图的所有点的度数都是偶数,那么想办法让图中的第一个点和最后一个点度数变为奇数,其他点的度数都是偶数。这个就比较巧妙,去掉从第一个点到最后一个点的一条无重复点的路径,除了起点和终点度数减1,其它点的度数都减2,目的就达到了。由于题目要求最后走的边的权值和最大,所以去掉的边的权值尽量小,那么从起点到终点求一个最短路即可。

求路径的方法是首先标记最短路上的边,然后从起点或终点开始dfs,走过的每条边标记(注意这是无向图,所以反向路径也要标记),当一个点再无边可走的时候,就把它放入路径中,这样可以保证求出的一定是一个欧拉道路。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 305;
const int inf = 0x3f3f3f3f; struct edge
{
int u,v,cost;
edge(int u,int v,int cost):u(u),v(v),cost(cost){}
edge(){}
}; int a[N][N],b[N][N],c[N][N];
int mp[N][N]; vector<edge> es;
vector<int> G[N*N];
vector<pii> anc; void adde(int u,int v,int cost)
{
es.push_back(edge(u,v,cost));
es.push_back(edge(v,u,cost));
int sz = es.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
} ll dis[N*N];
int rev[N*N];
bool vis[N*N];
bool used[N*N*8];
pii rid[N*N]; int cnt; void spfa()
{
for (int i = 0;i <= cnt;i++) dis[i] = 1e18;
memset(vis,0,sizeof(vis));
memset(rev,0,sizeof(rev));
vis[1] = 1;
dis[1] = 0;
queue<int> q;
q.push(1);
while (!q.empty())
{
int u = q.front();
q.pop();
vis[u] = 0;
for (int i = 0;i < G[u].size();i++)
{
edge &e = es[G[u][i]];
int v = e.v;
if (dis[v] > dis[u] + e.cost)
{
dis[v] = dis[u] + e.cost;
rev[v] = G[u][i];
if (!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
}
}
} void dfs(int u)
{
for (int i = 0;i < G[u].size();i++)
{
int id = G[u][i];
edge &e = es[id];
if (!used[id])
{
used[id] = used[id^1] = 1;
int v = e.v;
dfs(v);
}
}
anc.push_back(rid[u]);
} void init()
{
cnt = 0;
anc.clear();
es.clear();
for (int i = 0;i < N * N;i++) G[i].clear();
} int main()
{
int t;
scanf("%d",&t);
while (t--)
{
int n;
scanf("%d",&n);
init();
ll ans = 0;
for (int i = 1;i < n;i++)
{
for (int j = 1;j <= i;j++)
{
scanf("%d",&a[i][j]);
ans += a[i][j];
}
}
for (int i = 1;i < n;i++)
{
for (int j = 1;j <= i;j++)
{
scanf("%d",&b[i][j]);
ans += b[i][j];
}
}
for (int i = 1;i < n;i++)
{
for (int j = 1;j <= i;j++)
{
scanf("%d",&c[i][j]);
ans += c[i][j];
}
} for (int i = 1;i <= n;i++)
{
for (int j = 1;j <= i;j++)
{
mp[i][j] = ++cnt;
rid[cnt] = pii(i,j);
}
}
for (int i = 1;i < n;i++)
{
for (int j = 1;j <= i;j++)
{
int x = mp[i][j];
int y = mp[i+1][j];
adde(x,y,a[i][j]);
y = mp[i+1][j+1];
adde(x,y,b[i][j]);
x = mp[i+1][j];
y = mp[i+1][j+1];
adde(x,y,c[i][j]);
}
}
spfa();
ans -= dis[cnt];
memset(used,0,sizeof(used));
for (int i = cnt;i != 1;i = es[rev[i]].u)
{
used[rev[i]] = used[rev[i]^1] = 1;
}
dfs(cnt);
printf("%lld\n",ans);
printf("%d\n",(int)anc.size());
for (int i = 0;i < anc.size();i++)
{
printf("%d %d%c",anc[i].first,anc[i].second,i == anc.size() - 1 ? '\n' : ' ');
}
}
return 0;
}

zoj 4122 Triangle City 2019山东省赛J题的更多相关文章

  1. 山东省赛J题:Contest Print Server

    Description In ACM/ICPC on-site contests ,3 students share 1 computer,so you can print your source c ...

  2. 2013年山东省赛F题 Mountain Subsequences

    2013年山东省赛F题 Mountain Subsequences先说n^2做法,从第1个,(假设当前是第i个)到第i-1个位置上哪些比第i位的小,那也就意味着a[i]可以接在它后面,f1[i]表示从 ...

  3. hdu6578 2019湖南省赛D题Modulo Nine 经典dp

    目录 题目 解析 AC_Code @ 题目 第一题题意是一共有{0,1,2,3}四种数字供选择,问有多少个长度为n的序列满足所有m个条件,每个条件是说区间[L,R]内必须有恰好x个不同的数字. 第二题 ...

  4. HEX SDUT 3896 17年山东省赛D题

    HEX SDUT 3896 17年山东省赛D题这个题是从矩形的左下角走到右上角的方案数的变形题,看来我对以前做过的题理解还不是太深,或者是忘了.对于这种题目,直接分析它的性质就完事了.从(1,1)走到 ...

  5. luogu 1327 数列排序 & 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 J题 循环节

    luogu 1327 数列排序 题意 给定一个数列\(\{an\}\),这个数列满足\(ai≠aj(i≠j)\),现在要求你把这个数列从小到大排序,每次允许你交换其中任意一对数,请问最少需要几次交换? ...

  6. HDU 4800/zoj 3735 Josephina and RPG 2013 长沙现场赛J题

    第一年参加现场赛,比赛的时候就A了这一道,基本全场都A的签到题竟然A不出来,结果题目重现的时候1A,好受打击 ORZ..... 题目链接:http://acm.hdu.edu.cn/showprobl ...

  7. 模拟 2013年山东省赛 J Contest Print Server

    题目传送门 /* 题意:每支队伍需求打印机打印n张纸,当打印纸数累计到s时,打印机崩溃,打印出当前打印的纸数,s更新为(s*x+y)%mod 累计数清空为0,重新累计 模拟简单题:关键看懂题意 注意: ...

  8. The 10th Shandong Provincial Collegiate Programming Contest 2019山东省赛游记+解题报告

    比赛结束了几天...这篇博客其实比完就想写了...但是想等补完可做题顺便po上题解... 5.10晚的动车到了济南,没带外套有点凉.酒店还不错. 5.11早上去报道,济南大学好大啊...感觉走了一个世 ...

  9. [2019上海网络赛J题]Stone game

    题目链接 CSLnb! 题意是求出给定集合中有多少个合法子集,合法子集的定义为,子集和>=总和-子集和$\& \&$子集和-(子集的子集和)<=总和-子集和. 其实就是很简 ...

随机推荐

  1. 《基于TCP交换的电路交换与分组交换融合方法》读书笔记

    简介 在论文<Is IP going to take over the world (of communications)?>中作者对IP相关的一些说法(假设)提出了质疑,并得出结论:虽然 ...

  2. 【CodeForces - 939A】Love Triangle(模拟)

    Love Triangle Descriptions: 正如你所知道的,没有男性飞机也没有女性飞机.然而,地球上的每一个平面都喜欢另一个平面.地球上有n个平面,编号从1到n,编号i的平面喜欢编号fi的 ...

  3. 【VS开发】ConvertBSTRToString(filename) 不能将string转换为BSTR

    环境:win7,x64,vs2008 sp1 把VC 6.0的工程文件用VS2008打开,编译报错: error C2664:"_com_util::ConvertBSTRToString& ...

  4. HDU 1688 Sightseeing 【输出最短路+次短路条数】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1688 题目大意:给n个点,m条有向边.再给出起点s, 终点t.求出s到t的最短路条数+次短路条数. 思 ...

  5. Oooooooo AAAAE 【网络流最小点权覆盖】

    Description “Let the bass kick!O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee- ...

  6. 学习笔记:html学习之一:html基本标记

    1. 概论 一个完整的 HTML 文档必须包含 3 个部分: 一个由 元素定义的文档版本信息. 一个由 定义各项声明的文档头部, 作为各种声明信息的包含元素出现在文档的顶端,并且要先于 出现. 一个由 ...

  7. shell 数组长度

    Shell  数组操作方式 数组元素个数  ${#array[@]}  数组的所有元素  ${array[*]}  字符串长度      ${#str} 1.获取数组元素的个数: array=(bil ...

  8. dev控件学习笔记之----CxGrid

    本人总结的DEV学习:希望对大家有所帮助. 一.是否显示分组工具: 二.表格左边记录信息显示的宽度: 三.设置表格行高: 四.表头文件的水平和垂直设置:多个设置用按住SHIFT后进行多选,然后就可以设 ...

  9. Servlet 过滤器和异常处理

    Servlet 编写过滤器 Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息.可以将一个或多个 Servlet 过滤器附加到一个 Servlet 或一组 Servl ...

  10. spark算子篇-repartition and coalesce

    我们知道 RDD 是分区的,但有时候我们需要重新设置分区数量,增大还是减少需要结合实际场景,还有可以通过设置 RDD 分区数来指定生成的文件的数量 重新分区有两种方法:repartition and ...