題意:
有乙個圖,給圖上每個頂點都賦乙個實數ai。如果存在乙個正整數t滿足下面兩個條件,這個圖就是乙個"difference"。
1. |ai| <= t。
2. 如果點i,j構成的邊在圖中存在,則 |ai - aj| >= t;否則 |ai - aj| " 代表充要條件)
給出圖,問這個圖是否是乙個"difference"。
思路:
結合前兩個條件,顯然每條邊的兩個端點值都要一正一負,用dfs給每個頂點打上標記colors(1表示值為正,2表示值為負)。
如果圖中存在奇數邊的環一定無解,可以在dfs的時候進行剪枝,能夠讓執行時間快一大半。
然後是遍歷每個點對(i,j),有下面四種情況:
1. 邊ij存在,且點i為正,則 ai - aj >= t
2. 邊ij存在,且點i為負,則 aj - ai >= t
3. 邊ij不存在,且點i為正,則 ai - aj <= t - 1
4. 邊ij不存在,且點i為負,則 aj - ai <= t - 1
僅僅是上面的不等式建的圖不一定連通,我們可以增加超級源點0,設a0 = 0,那麼就有下面兩種情況:
1. 點i為正時,0 <= ai - a0 <= t - 1
2. 點i為負時,0 <= a0 - ai <= t - 1
t的值不重要,取超過點數即可。
用上面兩組不等式建圖,然後spfa判負環即可。
#include #include #include #include #include #include #include #include #include #include #include #include using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 1005;
struct edgg[90005];
int tot, pre[305];
void add(int u, int v, int w)
int g[305][305], flag, n, times[305], colors[305], dis[305];
bool vis[305];
void dfs(int x, int k)
colors[x] = k;
vis[x] = true;
for (int i = 1; i <= n; ++i) else }}
if (flag)
}}bool spfa()
times[0] = 1;
vis[0] = true;
dis[0] = 0;
queueque;
que.push(0);
while (!que.empty())
vis[v] = true;
que.push(v);}}
}}return true;
}int main()
}flag = 0;
memset(colors, 0, sizeof(colors));
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; ++i)
if (flag) break;
}if (flag)
tot = 0;
memset(pre, -1, sizeof(pre));
for (int i = 1; i <= n; ++i) else
} else else }}
if (colors[i] == 1) else
}puts(spfa() ? "yes" : "no");
}return 0;
}
這道題只用差分約束,不寫判奇環也能過,但時間要慢一些。下面乙個是帶剪枝的,上面乙個是不判奇環的。
BZOJ HNOI2005 狡猾的商人(差分約束)
time limit 10 sec memory limit 162 mb submit 4969 solved 2496 submit status discuss 刁奼接到乙個任務,為稅務部門調查一位商人的賬本,看看賬本是不是偽造的。賬本上記錄了n個月以來的收入情況,其中第i 個月的收入額為ai...
BZOJ HNOI2005 狡猾的商人(差分約束)
time limit 10 sec memory limit 162 mb submit 4969 solved 2496 submit status discuss 刁奼接到乙個任務,為稅務部門調查一位商人的賬本,看看賬本是不是偽造的。賬本上記錄了n個月以來的收入情況,其中第i 個月的收入額為ai...
差分約束 hdu 3666
xij ai l bj 0 xij ai u bj 0 兩邊取對數來去除ai,bj前面的係數 有 logbj logai logxij logu logai log bj logl logxij 化成標準差分約束,建圖,spfa,注意乙個竅門,當入隊總數大於2 n m 時就可以輸出no 因為 乙個點...