luogu2761 软件补丁问题 状态压缩最短路径
关键词:状态压缩 最短路径
想不出快速办法,就先考虑考虑暴力。枚举每一种错误分布的情况,然后通过可用的补丁转化为另多种情况,这些情况又转化为更多种情况……我们可以用图来表示这种关系!
状态压缩:每个错误的状态可以压缩在一个整数里。
最短路径:如果一个状态可以用补丁变为另一种状态,则两个状态间连一条边,权值为补丁所需时间。
注意:二进制运算符,如&,|等,优先级比==低。所以有二进制运算时,等号左边记得要加括号。
#include <cstdio> #include <cstring> #include <cassert> #include <iostream> #include <queue> #include <vector> using namespace std; #define LOOP(i, n) for(int i=0; i<n; i++) const int MAX_STATE = 1 << 21, INF = 0x3f3f3f3f, MAX_BUG = 25, MAX_PATCH = 110; int TotBug, TotPatch; int HaveBug[MAX_PATCH], Normal[MAX_PATCH], Repair[MAX_PATCH], Add[MAX_PATCH]; int W[MAX_PATCH]; struct Node; struct Edge; struct Node { Edge *Head; int Dist, State; bool Inq; Node() :Dist(INF){} }_nodes[MAX_STATE];struct Edge { Node *To; Edge *Next; int Weight; Edge(Node *to, Edge *next, int weight) :To(to),Next(next),Weight(weight){} }; vector<Edge*> _edges; void AddEdge(int uId, int vId, int weight) { Node *from = uId + _nodes, *to = vId + _nodes; from->State = uId; to->State = vId; Edge *e = new Edge(to,from->Head,weight); _edges.push_back(e); from->Head = e; } void Build(Node *cur) { LOOP(patch, TotPatch) { if (((cur->State & HaveBug[patch]) == HaveBug[patch]) && ((~cur->State) & Normal[patch]) == Normal[patch]) { int newState = ((~Repair[patch])&cur->State) | Add[patch]; if (cur->State != newState) AddEdge(cur->State, ((~Repair[patch])&cur->State) | Add[patch], W[patch]); } } } void SPFA() { static queue<Node*> q; int curState = (1 << TotBug) - 1; Node *cur = curState + _nodes; cur->State = curState; cur->Dist = 0; Build(cur); cur->Inq = true; q.push(cur); while (!q.empty()) { cur = q.front(); q.pop(); if (cur->Inq) cur->Inq = false; for (Edge *e = cur->Head; e; e = e->Next) { if (cur->Dist + e->Weight < e->To->Dist) { if (e->To->Dist == INF) Build(e->To); e->To->Dist = cur->Dist + e->Weight; if (!e->To->Inq) { e->To->Inq = true; q.push(e->To); } } } } } int main() { scanf("%d%d", &TotBug, &TotPatch); char b[100], f[100]; LOOP(patch, TotPatch) { scanf("%d %s %s", &W[patch], b, f); LOOP(bug, TotBug) { if (b[bug] == '+') HaveBug[patch] |= (1 << bug); else if (b[bug] == '-') Normal[patch] |= (1 << bug); if (f[bug] == '+') Add[patch] |= (1 << bug); else if (f[bug] == '-') Repair[patch] |= (1 << bug); } } SPFA(); printf("%d\n", _nodes[0].Dist == INF ? 0 : _nodes[0].Dist); return 0; }