ABC 394
目录
E. Palindromic Shortest Path
F. Alkane
E. Palindromic Shortest Path
如果正着想,从 i 到 j 有没有回文串路径,太复杂。
换一种思路,目标是找出所有回文路径,同时记录新增回文路径的两端点对应答案。
具体方法是从路径长为 0 和 1的所有情况开始扩散,就是 bfs,每次取出一条路径的两个端点 u 和 v,检查有没有一个点 x 到 u 的字符等于 v到一个点 y 的字符,若有并且 x 到 y 还没有答案,则更新 x 到 y的答案。因为路径一定是越来越长,因此第一次更新过的两个点后面不可能再被更新。
一定要把(i,i)也就是路径长度为 0 的先入队,不能放在循环里入,要确保这些对在队列最前面,也是最先取出。没有了长度为 0 的再开始取长度为 1 的。长度为 0 和 1 的都是预处理进去的。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 105, INF = 1e18;
struct node
{
int u, v, size;
};
int T, n, cnt, ans[N][N], vis[N][N];
char a[N][N];
queue<node> q;
signed main()
{
cin >> n;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
ans[i][j] = -1;
for (int i = 1; i <= n; i ++)
q.push({i, i, 0}), ans[i][i] = 0, vis[i][i] = 1;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
{
cin >> a[i][j];
if (a[i][j] != '-' && i != j)
q.push({i, j, 1}), ans[i][j] = 1, vis[i][j] = 1;
}
while (!q.empty())
{
node t = q.front(); q.pop();
int u = t.u, v = t.v, s = t.size;
for (int i = 1; i <= n; i ++)
if (a[i][u] != '-')
for (int j = 1; j <= n; j ++)
if (a[i][u] == a[v][j] && vis[i][j] == 0)
q.push({i, j, s + 2}), ans[i][j] = s + 2, vis[i][j] = 1;
}
for (int i = 1; i <= n; i ++)
{
for(int j = 1; j <= n; j ++)
cout << ans[i][j] << ' ';
cout << endl;
}
return 0;
}
F. Alkane
画几个烷烃会发现,设度数为 4 的点为主干,有 x 个,则总结点数是 3 * x + 2。因此我们只需要找到主干最多多少个。
一个点在选出来的子图上能作为主干,那么它在原图上的度数一定大于等于 4。因此我在 dfs 树的时候只看度数大于等于 4 的点。
dp [ u ] [ 0 ] :u 是根节点,他选 4 个儿子(如果有 4 个儿子的话,不足就是全选)
dp [ u ] [ 1 ] :u 不是根节点,他还要留一条边给父节点,他只能选最大的 3 个儿子
dp 里面存的是主干节点的个数,和任何叶子结点都无关!
那么如何增加选择的子图中一个点只能有 4 个度?就体现在转移方程的时候,对每个主干点只选 3 个或者 4 个儿子。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5, INF = 1e18;
int T, n, cnt, ans, d[N], vis[N], dp[N][2];
string s;
vector<int> G[N];
void dfs(int u)
{
vis[u] = 1;
vector<int> t;
for (int i = 0; i < G[u].size(); i ++)
{
int v = G[u][i];
if (d[v] >= 4 && vis[v] == 0)
{
dfs(v);
t.push_back(dp[v][1]);
}
}
sort(t.begin(), t.end(), greater<int>());
for (int i = 0; i < t.size() && i < 3; i ++) // 不一定有 3 个度数大于等于 4 的儿子
dp[u][1] += t[i];
dp[u][0] = dp[u][1];
if (t.size() >= 4)
dp[u][0] += t[3];
}
signed main()
{
cin >> n;
for (int i = 1; i <= n; i ++)
dp[i][1] = 1;
for (int i = 1; i < n; i ++)
{
int u, v;
cin >> u >> v;
G[u].push_back(v), G[v].push_back(u);
d[u] ++, d[v] ++;
}
for (int i = 1; i <= n; i ++)
if (d[i] >= 4 && vis[i] == 0)
dfs(i);
for (int i = 1; i <= n; i ++)
ans = max(ans, dp[i][0]);
if (ans == 0)
cout << "-1";
else
cout << ans * 3 + 2;
return 0;
}