num1:C++
code:#include

include

include

include

include

using namespace std;

struct Edge {
int to, time;
};

int findBestStarter(int n, vector<vector>& graph) {
vector minTime(n + 1, INT_MAX);
vector visited(n + 1, false);
int bestStarter = -1;
int minOverallTime = INT_MAX;

for (int start = 1; start <= n; ++start) {
    queue<pair<int, int>> q; 
    memset(visited, false, sizeof(visited));
    q.push({start, 0});
    visited[start] = true;
    minTime[start] = 0;

    while (!q.empty()) {
        int current = q.front().first;
        int currentTime = q.front().second;
        q.pop();

        for (const auto& edge : graph[current]) {
            int next = edge.to;
            int time = edge.time;

            if (!visited[next]) {
                visited[next] = true;
                q.push({next, currentTime + time});
                minTime[next] = currentTime + time;
            }
        }
    }

    bool allReachable = true;
    for (int i = 1; i <= n; ++i) {
        if (minTime[i] == INT_MAX) {
            allReachable = false;
            break;
        }
        minOverallTime = min(minOverallTime, minTime[i]);
    }

    if (allReachable && minOverallTime < INT_MAX) {
        if (bestStarter == -1 || minTime[start] < minTime[bestStarter]) {
            bestStarter = start;
        } else if (minTime[start] == minTime[bestStarter] && start < bestStarter) {
            bestStarter = start;
        }
    }
}

if (bestStarter == -1) {
    return -2; 
} else {
    return minOverallTime;
}

}

int main() {
while (true) {
int n;
cin >> n;
if (n == 0) break;

    vector<vector<Edge>> graph(n + 1);

    for (int i = 1; i <= n; ++i) {
        int m;
        cin >> m;
        for (int j = 0; j < m; ++j) {
            int to, time;
            cin >> to >> time;
            graph[i].push_back({to, time});
        }
    }

    int result = findBestStarter(n, graph);
    if (result == -2) {
        cout << "disjoint" << endl;
    } else {
     
        cout << result << endl;
    }
}

return 0;

}
解题思路:对于给定的经纪人网络,我们需要找到一个起始经纪人,使得信息从这个经纪人传播到所有其他经纪人的最大时间最小。这可以通过对每个经纪人进行宽度优先搜索(BFS)来实现,以计算从该经纪人到所有其他经纪人的最短时间。我们遍历每个经纪人作为起始点,记录从该起始点到所有其他经纪人的最短时间,并更新全局最小最大时间。同时,检查是否存在无法从某个起始点到达的经纪人。如果存在这样的经纪人,则输出"disjoint"。否则,输出全局最小最大时间。

num2:C++
code:#include

include

include

using namespace std;
const int MAXN = 100005;
vector adj[MAXN];
bool visited[MAXN];
int dist[MAXN];
void dfs(int node, int parent, int &maxDist, int &farthestNode) {
visited[node] = true;
if (dist[node] > maxDist) {
maxDist = dist[node];
farthestNode = node;
}
for (int neighbor : adj[node]) {
if (!visited[neighbor]) {
dist[neighbor] = dist[node] + 1;
dfs(neighbor, node, maxDist, farthestNode);
}
}
}

int main() {
int n;
cin >> n;
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
fill(visited, visited + MAXN, false);
fill(dist, dist + MAXN, 0);
int maxDistA = 0, farthestNodeA = 0;
dfs(1, -1, maxDistA, farthestNodeA);
fill(visited, visited + MAXN, false);
fill(dist, dist + MAXN, 0);
int maxDistB = 0;
dfs(farthestNodeA, -1, maxDistB, ignore);
cout << maxDistB - 1 << endl;

return 0;

}
解题思路:为了找到无向树的直径,我们首先任意选择一个节点(例如节点1)作为起点,进行深度优先搜索(DFS),标记从该节点出发能够到达的最远节点farthestNodeA。这个过程中,我们记录了从起点到每个节点的距离。随后,我们从farthestNodeA出发,再次进行DFS,这次是为了找到从farthestNodeA出发能够到达的最远距离,这个距离实际上就是树的直径。由于我们是从farthestNodeA出发,所以得到的最大距离直接就是直径,但通常树的边数会比直径少1(因为直径是经过的边数),所以输出时需要减1(但在此问题中,由于我们是计算路径长度,所以直接输出最大距离即可)

num3:C++
code:#include

include

include

include

using namespace std;

typedef long long ll;
typedef pair<ll, ll> pii;

const ll INF = LLONG_MAX;

vector dijkstra(ll start, ll n, vector<vector>& adj) {
vector dist(n + 1, INF);
priority_queue<pii, vector, greater> pq;

dist[start] = 0;
pq.push({0, start});

while (!pq.empty()) {
    ll u = pq.top().second;
    ll d = pq.top().first;
    pq.pop();

    if (d > dist[u]) continue;

    for (auto& edge : adj[u]) {
        ll v = edge.first;
        ll w = edge.second;

        if (dist[u] + w < dist[v]) {
            dist[v] = dist[u] + w;
            pq.push({dist[v], v});
        }
    }
}

return dist;

}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);

ll N;
cin >> N;

while (N--) {
    ll P, Q;
    cin >> P >> Q;

    vector<vector<pii>> adj(P + 1);
    vector<vector<pii>> adj_rev(P + 1);

    for (ll i = 0; i < Q; ++i) {
        ll u, v, w;
        cin >> u >> v >> w;
        adj[u].push_back({v, w});
        adj_rev[v].push_back({u, w});
    }

    vector<ll> dist_from_ccs = dijkstra(1, P, adj);

    vector<ll> dist_to_ccs = dijkstra(1, P, adj_rev);

 
    for (ll i = 1; i <= P; ++i) {
        total_cost += dist_from_ccs[i] + dist_to_ccs[i];
    }

    cout << total_cost << "\n";
}

return 0;

}
解题思路:若求树的直径,应选任意节点为起点,DFS找最远节点A,再以A为起点DFS找最远路径,该路径即为直径。若处理图,Dijkstra算法可求单源最短路径,但需明确目标和起点。

num4:C++
code:#include

include

include

include

include

include

include

define N 7000

using namespace std;
inline void read(int &x)
{
x=0;
int p=1;
char c=getchar();
while(!isdigit(c)){if(c=='-')p=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+(c^'0');c=getchar();}
x*=p;
}
int n;
int to[N],beg[N],nex[N],match[N];
int vis[N];
int e;
int ans;
void add(int x,int y)
{
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
}
int dfs(int x)
{
for(int i=beg[x];i;i=nex[i])
{
int y=to[i];
if(!vis[y])
{
vis[y]=1;
if(!match[y]||dfs(match[y]))
{
match[y]=x;
return 1;
}
}
}
return 0;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(beg,0,sizeof(beg));
e=0;
for(int i=1;i<=n;i++)
{
int x,gs;
read(x);
read(gs);
x++;
int y;
for(int j=1;j<=gs;j++)read(y),y++,add(x,y),add(y,x);
}
ans=0;
memset(match,0,sizeof(match));
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i))ans++;
}
printf("%d\n",ans/2);
}
return 0;
}
解题思路:采用匈牙利算法求解二分图的最大匹配问题。首先,通过输入构建二分图的邻接表表示。然后,对每个节点尝试进行深度优先搜索(DFS),寻找增广路径以扩大匹配。在DFS过程中,使用vis数组标记已访问节点,避免重复访问。若找到增广路径,则更新匹配,并返回成功标志。最终,最大匹配数即为成功匹配的节点对数的一半(因每条边连接两个节点,但匹配按边计算)。注意,输入处理时需将节点编号自增1以适配数组下标从1开始的习惯。

num5:C++
code:#include

include

include

include

include

include

include

include

int Read()
{
int x=0;char c=getchar();
while(!isdigit(c))
{
c=getchar();
}
while(isdigit(c))
{
x=x*10+(c^48);
c=getchar();
}
return x;
}

using std::priority_queue;
using std::pair;
using std::vector;
using std::make_pair;
using std::greater;

struct Edge
{
int to,next,cost;
}edge[2500001];
int cnt,head[110005];

void add_edge(int u,int v,int c=0)
{
edge[++cnt]=(Edge){v,head[u],c};
head[u]=cnt;
}

int dis[110005];
bool vis[110005];
void Dijkstra(int s)
{
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > points;
points.push(make_pair(0,s));
while(!points.empty())
{
int u=points.top().second;
points.pop();
if(!vis[u])
{
vis[u]=1;
for(int i=head[u];i;i=edge[i].next)
{
int to=edge[i].to;
if(dis[to]>dis[u]+edge[i].cost)
{
dis[to]=dis[u]+edge[i].cost;
points.push(make_pair(dis[to],to));
}
}
}
}
}

int main()
{
int n=Read(),m=Read(),k=Read(),s=Read(),t=Read();
int u,v,c;
for(int i=0;i<m;++i)
{
u=Read(),v=Read(),c=Read();
add_edge(u,v,c);
add_edge(v,u,c);
for(int j=1;j<=k;++j)
{
add_edge(u+(j-1)n,v+jn);
add_edge(v+(j-1)n,u+jn);
add_edge(u+jn,v+jn,c);
add_edge(v+jn,u+jn,c);
}
}
for(int i=1;i<=k;++i)
{
add_edge(t+(i-1)n,t+in);
}
Dijkstra(s);
printf("%d",dis[t+k*n]);
return 0;
}
解题思路:通过Dijkstra算法求解加权图中单源最短路径。但图中存在特殊“分层”结构,需特别注意。首先,构建图的邻接表,包括原始边和分层间边。然后,初始化距离数组并设置起点距离为0。利用优先队列实现Dijkstra算法,每次取出当前最短路径节点,更新其邻接节点的距离。特别注意,分层间边也需考虑,因其影响最短路径计算。最后,得到终点在分层图中对应节点的最短距离,即为所求。注意,节点编号需映射到数组下标,且图可能较稠密,需优化内存使用。

num6:C++
code:#include

include

include

include

include

define ll long long

define gc getchar

define maxn 105

using namespace std;

inline ll read(){
ll a=0;int f=0;char p=gc();
while(!isdigit(p)){f|=p=='-';p=gc();}
while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
return f?-a:a;
}int n,m,f[maxn][maxn];

struct ahaha{
int w,to,next;
}e[maxn<<1];int tot,head[maxn];
inline void add(int u,int v,int w){
e[tot]={w,v,head[u]};head[u]=tot++;
}

int sz[maxn];
void dfs(int u,int fa){
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;if(v==fa)continue;
dfs(v,u);sz[u]+=sz[v]+1;
for(int j=min(sz[u],m);j;--j)
for(int k=min(sz[v],j-1);k>=0;--k)
f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+e[i].w);
}
}

int main(){memset(head,-1,sizeof head);
n=read();m=read();
for(int i=1;i<n;++i){
int u=read(),v=read(),w=read();
add(u,v,w);add(v,u,w);
}
dfs(1,-1);
printf("%d\n",f[1][m]);
return 0;
}
解题思路:采用树形动态规划求解在树中选择不超过m条边,使得这些边及其连接的节点上的权值之和最大。首先,构建树的邻接表表示,并初始化动态规划数组f[u][j]表示以节点u为根的子树中,选择不超过j条边时的最大权值和。然后,通过深度优先搜索遍历树,在遍历过程中更新动态规划数组。对于每个节点,枚举其子树中选择边的数量,并计算最大权值和。最终,f[1][m]即为所求结果。

posted on 2025-02-19 16:21  Penson2025cpc  阅读(11)  评论(0)    收藏  举报