<p class="hint">Five items, A–E, are for sale. Each bid names a price for a <b>bundle</b>. Accept bids to earn their price — but two accepted bids may never share an item. Maximize revenue, then let the computer brute-force the best set.</p>
<div id="bids" class="bids"></div>
<div class="totals">
<div class="t"><span>Your revenue</span><b id="rev">$0M</b></div>
<div class="t"><span>Optimal</span><b id="opt">?</b></div>
</div>
<div class="status" id="status">Click bids to accept them.</div>
<div class="btns">
<button id="find" type="button">Find optimal</button>
<button id="reset" type="button" class="ghost">Clear</button>
</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.bids { display: flex; flex-direction: column; gap: 6px; margin: .4rem 0; }
.bid { display: flex; align-items: center; gap: 10px; padding: .5rem .7rem;
border: 1px solid #cdd9e3; border-radius: 10px; background: #f3f6f9; cursor: pointer;
transition: all .12s; }
.bid:hover { background: #e8eef3; }
.bid.on { background: #1d3557; border-color: #16283f; color: #fff; }
.bid.blocked { opacity: .45; }
.bundle { display: flex; gap: 4px; }
.item { width: 26px; height: 26px; display: flex; align-items: center; justify-content: center;
font: 700 13px ui-monospace, monospace; border-radius: 6px; background: #dfe7ee; color: #1d3557; }
.bid.on .item { background: #2c4a6e; color: #fff; }
.price { margin-left: auto; font: 700 15px system-ui, sans-serif; }
.totals { display: flex; gap: 1.4rem; margin: .7rem 0 .2rem; }
.t { font-size: .85rem; color: #555; }
.t b { display: block; font-size: 1.3rem; color: #1d3557; }
.status { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c92f3c; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Combinatorial-auction WINNER DETERMINATION. Each bid is a price on a bundle of items. A feasible accept-set is a set of bids that are pairwise item-disjoint (no item sold twice). Goal: maximize total price. This is weighted set packing / weighted independent set — NP-hard. Checking a set is a quick scan; finding the optimum brute-forces all 2^m subsets of the m bids.
const ITEMS = ['A','B','C','D','E'];
const BIDS = [
{ id:0, set:['A','B'], price:7 },
{ id:1, set:['C'], price:4 },
{ id:2, set:['B','C','D'], price:9 },
{ id:3, set:['A'], price:5 },
{ id:4, set:['D','E'], price:6 },
{ id:5, set:['E'], price:3 },
{ id:6, set:['A','C','E'], price:10 }
];
BIDS.forEach(b => b.mask = b.set.reduce((m,i)=> m | (1 << ITEMS.indexOf(i)), 0));
const accepted = new Set();
// Feasible iff no two accepted bids share an item.
function usedMask(exclude){ let m=0; for(const id of accepted){ if(id===exclude) continue; m |= BIDS[id].mask; } return m; }
function revenue(){ let s=0; for(const id of accepted) s += BIDS[id].price; return s; }
function render(){
const wrap = document.getElementById('bids'); wrap.innerHTML='';
const others = usedMask(-2); // mask of all accepted bids
BIDS.forEach(b => {
const on = accepted.has(b.id);
// a non-accepted bid is "blocked" if it collides with the current accept-set
const collides = !on && (b.mask & usedMask(-1)) !== 0;
const div = document.createElement('div');
div.className = 'bid' + (on?' on':'') + (collides?' blocked':'');
const bundle = b.set.map(i=>`<span class="item">${i}</span>`).join('');
div.innerHTML = `<div class="bundle">${bundle}</div><span class="price">${b.price}M</span>`;
div.addEventListener('click', ()=>{
if(on){ accepted.delete(b.id); }
else { if((b.mask & usedMask(-1))!==0){ setStatus('That bundle shares an item with one you already accepted.','bad'); render(); return; } accepted.add(b.id); }
update(); render();
});
wrap.appendChild(div);
});
document.getElementById('rev').textContent = '
Notice the asymmetry. Checking your choice is effortless: confirm no item is sold twice, then add up the prices. Finding the accept-set that maximizes revenue is the hard part — press Find optimal and the computer tries every subset of bids that fits. With a handful of bids that is fine; add more overlapping bundles and the number of combinations explodes, the same wall you meet in P vs NP.
+revenue()+'M';
}
function setStatus(t,cls){ const s=document.getElementById('status'); s.textContent=t; s.className='status '+cls; }
function update(){
const r = revenue();
if(r===0) setStatus('Click bids to accept them.','');
else setStatus(fmt('Accepted set is valid — revenue $%r%M.', { r: r }),'ok');
}
// Brute force: best item-disjoint subset of bids.
function findOptimal(){
let best=0, bestSet=0, steps=0;
for(let s=0; s<(1<<BIDS.length); s++){ steps++;
let used=0, val=0, ok=true;
for(let i=0;i<BIDS.length;i++) if(s&(1<<i)){
if(used & BIDS[i].mask){ ok=false; break; }
used |= BIDS[i].mask; val += BIDS[i].price;
}
if(ok && val>best){ best=val; bestSet=s; }
}
accepted.clear();
for(let i=0;i<BIDS.length;i++) if(bestSet&(1<<i)) accepted.add(i);
document.getElementById('opt').textContent = '
Notice the asymmetry. Checking your choice is effortless: confirm no item is sold twice, then add up the prices. Finding the accept-set that maximizes revenue is the hard part — press Find optimal and the computer tries every subset of bids that fits. With a handful of bids that is fine; add more overlapping bundles and the number of combinations explodes, the same wall you meet in P vs NP.
+best+'M';
render();
setStatus(fmt('Optimal revenue $%best%M, found after checking %steps% of %v% subsets.', { best: best, steps: steps, v: 1<<BIDS.length }),'ok');
console.log('Optimal:', best, 'bids:', [...accepted].join(' '), '| checked', steps, 'subsets');
}
document.getElementById('find').addEventListener('click', findOptimal);
document.getElementById('reset').addEventListener('click', ()=>{ accepted.clear(); document.getElementById('opt').textContent='?'; render(); setStatus('Click bids to accept them.',''); });
render();
<p class="hint">Five items, A–E, are for sale. Each bid names a price for a <b>bundle</b>. Accept bids to earn their price — but two accepted bids may never share an item. Maximize revenue, then let the computer brute-force the best set.</p>
<div id="bids" class="bids"></div>
<div class="totals">
<div class="t"><span>Your revenue</span><b id="rev">$0M</b></div>
<div class="t"><span>Optimal</span><b id="opt">?</b></div>
</div>
<div class="status" id="status">Click bids to accept them.</div>
<div class="btns">
<button id="find" type="button">Find optimal</button>
<button id="reset" type="button" class="ghost">Clear</button>
</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.bids { display: flex; flex-direction: column; gap: 6px; margin: .4rem 0; }
.bid { display: flex; align-items: center; gap: 10px; padding: .5rem .7rem;
border: 1px solid #cdd9e3; border-radius: 10px; background: #f3f6f9; cursor: pointer;
transition: all .12s; }
.bid:hover { background: #e8eef3; }
.bid.on { background: #1d3557; border-color: #16283f; color: #fff; }
.bid.blocked { opacity: .45; }
.bundle { display: flex; gap: 4px; }
.item { width: 26px; height: 26px; display: flex; align-items: center; justify-content: center;
font: 700 13px ui-monospace, monospace; border-radius: 6px; background: #dfe7ee; color: #1d3557; }
.bid.on .item { background: #2c4a6e; color: #fff; }
.price { margin-left: auto; font: 700 15px system-ui, sans-serif; }
.totals { display: flex; gap: 1.4rem; margin: .7rem 0 .2rem; }
.t { font-size: .85rem; color: #555; }
.t b { display: block; font-size: 1.3rem; color: #1d3557; }
.status { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c92f3c; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Combinatorial-auction WINNER DETERMINATION. Each bid is a price on a bundle of items. A feasible accept-set is a set of bids that are pairwise item-disjoint (no item sold twice). Goal: maximize total price. This is weighted set packing / weighted independent set — NP-hard. Checking a set is a quick scan; finding the optimum brute-forces all 2^m subsets of the m bids.
const ITEMS = ['A','B','C','D','E'];
const BIDS = [
{ id:0, set:['A','B'], price:7 },
{ id:1, set:['C'], price:4 },
{ id:2, set:['B','C','D'], price:9 },
{ id:3, set:['A'], price:5 },
{ id:4, set:['D','E'], price:6 },
{ id:5, set:['E'], price:3 },
{ id:6, set:['A','C','E'], price:10 }
];
BIDS.forEach(b => b.mask = b.set.reduce((m,i)=> m | (1 << ITEMS.indexOf(i)), 0));
const accepted = new Set();
// Feasible iff no two accepted bids share an item.
function usedMask(exclude){ let m=0; for(const id of accepted){ if(id===exclude) continue; m |= BIDS[id].mask; } return m; }
function revenue(){ let s=0; for(const id of accepted) s += BIDS[id].price; return s; }
function render(){
const wrap = document.getElementById('bids'); wrap.innerHTML='';
const others = usedMask(-2); // mask of all accepted bids
BIDS.forEach(b => {
const on = accepted.has(b.id);
// a non-accepted bid is "blocked" if it collides with the current accept-set
const collides = !on && (b.mask & usedMask(-1)) !== 0;
const div = document.createElement('div');
div.className = 'bid' + (on?' on':'') + (collides?' blocked':'');
const bundle = b.set.map(i=>`<span class="item">${i}</span>`).join('');
div.innerHTML = `<div class="bundle">${bundle}</div><span class="price">${b.price}M</span>`;
div.addEventListener('click', ()=>{
if(on){ accepted.delete(b.id); }
else { if((b.mask & usedMask(-1))!==0){ setStatus('That bundle shares an item with one you already accepted.','bad'); render(); return; } accepted.add(b.id); }
update(); render();
});
wrap.appendChild(div);
});
document.getElementById('rev').textContent = '
Notice the asymmetry. Checking your choice is effortless: confirm no item is sold twice, then add up the prices. Finding the accept-set that maximizes revenue is the hard part — press Find optimal and the computer tries every subset of bids that fits. With a handful of bids that is fine; add more overlapping bundles and the number of combinations explodes, the same wall you meet in P vs NP.
+revenue()+'M';
}
function setStatus(t,cls){ const s=document.getElementById('status'); s.textContent=t; s.className='status '+cls; }
function update(){
const r = revenue();
if(r===0) setStatus('Click bids to accept them.','');
else setStatus(fmt('Accepted set is valid — revenue $%r%M.', { r: r }),'ok');
}
// Brute force: best item-disjoint subset of bids.
function findOptimal(){
let best=0, bestSet=0, steps=0;
for(let s=0; s<(1<<BIDS.length); s++){ steps++;
let used=0, val=0, ok=true;
for(let i=0;i<BIDS.length;i++) if(s&(1<<i)){
if(used & BIDS[i].mask){ ok=false; break; }
used |= BIDS[i].mask; val += BIDS[i].price;
}
if(ok && val>best){ best=val; bestSet=s; }
}
accepted.clear();
for(let i=0;i<BIDS.length;i++) if(bestSet&(1<<i)) accepted.add(i);
document.getElementById('opt').textContent = '
Notice the asymmetry. Checking your choice is effortless: confirm no item is sold twice, then add up the prices. Finding the accept-set that maximizes revenue is the hard part — press Find optimal and the computer tries every subset of bids that fits. With a handful of bids that is fine; add more overlapping bundles and the number of combinations explodes, the same wall you meet in P vs NP.
+best+'M';
render();
setStatus(fmt('Optimal revenue $%best%M, found after checking %steps% of %v% subsets.', { best: best, steps: steps, v: 1<<BIDS.length }),'ok');
console.log('Optimal:', best, 'bids:', [...accepted].join(' '), '| checked', steps, 'subsets');
}
document.getElementById('find').addEventListener('click', findOptimal);
document.getElementById('reset').addEventListener('click', ()=>{ accepted.clear(); document.getElementById('opt').textContent='?'; render(); setStatus('Click bids to accept them.',''); });
render();